- •Архитектура современной вычислительной системы (обзор)
- •Кэши ассоциативные, с прямым отображением и множественно-ассоциативные
- •Представление бинарных данных
- •Режимы работы процессоров семейства i8086+
- •Регистры i8086+
- •Формат инструкции
- •Некоторые инструкции ЦПУ (не включая инструкции FPU, MMX, SSEn и пр.)
- •Формирование кодов основных инструкций i8086+
- •Соответствие мнемоники машинным кодам на примере инструкции пересылки (mov)
- •Режим реальных адресов i8086 (real mode)
- •Синтаксис основных ассемблеров (Intel и AT&T) семейства процессоров i8086+
- •Адреса: короткие, ближние, дальние; перемещаемые записи
- •Сегменты, секции, модели памяти, страницы
- •Переходы, вызовы процедур
- •Символы и макросы
- •Структура физического адресного пространства режима реальных адресов
- •Простейший пример BIOS
- •Некоторое оборудование IBM PC
- •Инициализация контроллера прерываний
- •Инициализация контроллеров клавиатуры PS/2
- •Инициализация PS/2 мыши
- •Инициализация таймера 8253/8254
- •Работа с последовательным интерфейсом UART
- •Программирование контроллера DMA 8257/8237
- •Прерывания в SMP системе; измерение времени
- •Инициализация локального контроллера прерываний (LAPIC)
- •Инициализация контроллера прерываний ввода-вывода (IO APIC)
- •Сегментная модель защищенных режимов i286...x64
- •Общая структура дескриптора
- •Cегмент состояния задачи; переключение стеков
- •«Нереальный 8086»
- •Системные вызовы
- •Структура адресного пространства многопоточного приложения (C, расширение MSVC) с обработкой исключений (Win32).
- •Структура адресного пространства многопоточного приложения (C++) с обработкой исключений (Posix Threads (NPTL); Linux; IA-32)
- •Страничная модель защищенных режимов i386...x64
- •Соглашения о вызовах C/C++ (платформы IA-32, x64)
- •Пример программы, демонстрирующей различные соглашения о вызовах.
- •Основные средства управления адресным пространством, основанные на страничном механизме
- •Запрет на исполнение данных
- •Пример использования уязвимости типа «переполнение буфера в стеке»
- •Проецирование файлов.
- •Императивный способ управления проецированием.
- •Пример создания разделяемого проецирования для межпроцессного взаимодействия
- •Исполняемые файлы и динамические библиотеки
- •Построение динамических библиотек
- •Загрузка библиотек на этапе исполнения.
- •Экспорт, импорт, перемещаемые записи в Windows
- •Экспорт, импорт, перемещаемые записи в Posix
- •POSIX. Позиционно-независимый код в архитектуре IA-32.
- •Построение и использование статических библиотек объектных файлов
- •Встроенный ассемблер; понятие барьеров оптимизации и барьеров памяти.
- •Пример измерения коротких интервалов времени
- •SMP, критические секции и взаимные блокировки
- •Литература
Загрузка библиотек на этапе исполнения. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
PIC-код |
|
|
|
|
|
||
Для архитектуры x86 характерно |
Определение |
|
Модификация кода и данных |
|
|
|
|
|
|
|
|
использование абсолютных адресов |
действительных адресов |
|
вследствие изменения адресов |
|
Описание перемещаемых |
|
Предзадание адресов |
||||
при обращении к данным, в случае |
только после определения |
|
статических переменных и процедур |
|
записей в исполняемом |
|
в момент сборки или при |
||||
косвенной адресации, а также при |
адреса загрузки библиотеки |
|
|
|
|
файле |
|
создании кэша библиотек |
|||
|
|
|
|||||||||
|
|
|
|
|
|
|
|
|
|
||
межсегментной передаче управления. |
|
|
Определение адресов импортируемых |
|
Прямое обращение к импортируемым символам |
|
|||||
В IA-32 относительный адрес используют только инструкции |
|
символов только после загрузки |
|
|
|||||||
|
|
|
|
|
|
|
|
||||
внутрисегментной передачи управления (ближние и короткие |
|
нужной разделяемой библиотеки |
|
|
|
|
|
|
|
||
|
|
Косвенное обращение через секции импорта |
|
|
|||||||
переходы, ближние вызовы) и только при прямой адресации |
|
|
|
|
|
||||||
|
|
|
|||||||||
|
|
|
|
|
|
|
|
|
|
||
(косвенные формы переходов и вызовов используют абсолютные адреса). В 64х разрядном режиме в частных случаях (ModR/M: 00...101) может использоваться адресация константным 32х разрядным смещением к RIP.
Код с перемещаемыми записями
#include <stdio.h> static int s_x;
void show_x( void )
{
printf("%d",add_x(0));
}
int add_x( int v )
{
return s_x += v;
}
В случае Visual Studio для указания экспортируемых символов использовался .def файл:
LIBRARY test EXPORTS
add_x show_x
Вместо использования .def файла можно было описать функции show_x и add_x с атрибутом
dllexport, например: void
__declspec(dllexport) show_x( void )
{
...
cl /O2 /Ox /LD /MD test.c /link /DEF:test.def
|
|
|
|
.686P |
|
|
.model |
flat |
PUBLIC |
_add_x |
|
PUBLIC |
??_C@_02EF@?$CFd?$AA@ |
|
PUBLIC |
_show_x |
|
EXTRN |
_printf:PROC |
|
_BSS |
SEGMENT |
|
_s_x |
DD |
01H DUP (?) |
_BSS |
ENDS |
|
CONST |
SEGMENT |
|
??_C@_02AMEF@?$CFd?$AA@ DB '%d',0 |
||
CONST |
ENDS |
|
_TEXT |
SEGMENT |
|
_v$ = 8 |
|
; size = 4 |
_add_x PROC |
|
|
|
mov |
eax, DWORD PTR _s_x |
|
add |
eax, DWORD PTR _v$[esp-4] |
|
mov |
DWORD PTR _s_x, eax |
|
ret |
0 |
_add_x ENDP |
|
|
_show_xPROC |
|
|
|
mov |
eax, DWORD PTR _s_x |
|
push |
eax |
|
push |
OFFSET ??_C@_02DEF@?$CFd?$AA@ |
|
call |
_printf |
|
add |
esp, 8 |
|
ret |
0 |
_show_xENDP |
|
|
_TEXT |
ENDS |
|
END |
|
|
gcc -O3 -fomit-frame-pointer -shared -o libtest.so test.c
|
|
|
.section |
.rodata.str1.1,"aMS" |
|
.LC0: .string"%d" |
|
|
.text |
|
|
.globl add_x |
|
|
.type |
add_x, @function |
|
add_x: |
|
|
movl |
4(%esp), %eax |
|
addl |
s_x, %eax |
|
movl |
%eax, s_x |
|
ret |
|
|
.globl show_x |
|
|
.type |
show_x, @function |
|
show_x: |
|
|
subl |
$12, %esp |
|
movl |
s_x, %eax |
|
movl |
$.LC0, (%esp) |
|
movl |
%eax, 4(%esp) |
|
call |
printf |
|
addl |
$12, %esp |
|
ret |
|
|
.local |
s_x |
|
.comm |
s_x,4,4 |
|
для получения ассемблерного кода использовались команды: cl /Fafile.asm /O2 /Ox /LD /MD test.c /link /DEF:test.def
и
gcc -O3 -fomit-frame-pointer -shared -S -o libtest.s test.c
Экспорт, импорт, перемещаемые записи в Windows
Отдельные поля из заголовка библиотеки:
|
|
|
|
|
|||
A00 size of code |
|
|
|
|
|||
C00 size of initialized data |
|
|
|
||||
13B5 |
entry point (100013B5) |
|
|
|
|||
1000 |
base |
of code |
|
|
|
|
|
2000 |
base |
of data |
|
|
|
|
|
10000000 image base (10000000 to 10004FFF) |
|
|
|
||||
24C0 |
[ 50] RVA [size] of Export Directory |
Import |
Address Table |
||||
217C |
[ 3C] RVA [size] of Import Directory |
||||||
4000 |
[ 130] RVA [size] of Base Relocation Directory |
|
(IAT) |
||||
20B0 |
[ 40] RVA [size] of Load Configuration Directory |
|
2000...2087 |
||||
2000 |
[ 88] RVA [size] of Import Address Table Directory |
|
|||||
Дизассемблериванный фрагмент секции .text: |
|
|
|
||||
10001000: mov |
eax, [10003010h] |
|
|
|
|||
10001005: add |
eax, [esp+4] |
|
Import Directory |
||||
10001008: mov |
[10003010h], eax |
|
|
217C...21B7 |
|||
1000100E: ret |
|
|
|
|
|||
10001010: mov |
eax, [10003010h] |
|
|
|
|||
10001015: push eax |
|
|
|
|
|||
10001016: push 100020A0 |
|
|
|
|
|||
1000101B: call 10001024h |
|
Import Lookup Table |
|||||
10001020: add esp, 8 |
|
||||||
10001023: ret |
|
|
|
|
(ILT) |
||
10001024: jmp [10002080] |
|
|
|
21B8...223F |
|||
Отдельные сведения об экспорте и импорте: |
|
|
|
||||
exports for qq.dll: |
|
|
|
|
|||
|
00000000 characteristics |
|
|
|
|||
|
4B14F093 time date stamp Tue Dec 01 13:31:47 2009 |
|
Strings |
||||
|
0.00 version |
|
|
|
|||
|
|
1 ordinal base |
|
|
|
2240...24BF |
|
|
|
2 number of functions |
|
|
|
||
|
|
2 number of names |
|
|
|
||
|
ordinal hint RVA |
name |
|
|
|
||
10 00001000 add_x
2 |
1 00001010 show_x |
Export Directory |
||
imports: |
|
|
||
|
|
24C0...24FF |
||
MSVCR90.dll |
|
|
|
|
|
1000203C Import Address Table |
|
|
|
|
100021F4 Import Name Table |
|
|
|
|
276 |
_lock |
|
|
|
... |
|
|
|
|
52E |
printf |
|
|
KERNEL32.dll |
|
|
|
|
|
10002000 Import Address Table |
|
|
|
|
100021B8 Import Name Table |
10000000 |
|
|
|
415 |
SetUnhandledExceptionFilter |
+00001000 |
|
|
… |
|
+(0FFF & 300A) |
|
(!) Import Name Table называют также Import |
|
|
||
1000100A |
||||
Lookup Table. В исполняемом файле IAT[i] равно ILT[i], а
во время загрузки образа в адресное пространство процесса загрузчик записывает в IAT[i] актуальный адрес импортируемой функции или данных.
.text |
|
|
|
|
|
|
|
|
|
|
|
|
ImageBaseAddress |
Для символов, описанных с |
||||
|
|
A1 |
10 |
30 |
00 |
10 |
03 |
44 |
24 |
|
||||||||
10001000: |
|
|
|
|
10000000 |
атрибутом |
|
|||||||||||
10001008: |
|
04 |
A3 |
10 |
30 |
00 |
10 |
C3 |
CC |
|
|
|||||||
10001010: |
|
|
A1 |
10 |
30 |
00 |
10 |
50 |
68 |
A0 |
|
адреса |
|
__declspec(dllimport) |
||||
10001018: |
|
20 |
00 |
10 |
E8 |
04 |
00 |
00 |
00 |
|
|
транслятор сразу генерирует |
||||||
|
|
вычислены в |
|
|||||||||||||||
10001020: |
|
83 |
C4 |
08 |
C3 |
FF 25 |
80 |
20 |
|
предположении |
|
инструкции с косвенной адресацией |
||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||||
10001028: |
00 |
10 |
8B |
FF |
56 |
68 |
80 |
00 |
|
загрузки библиотеки |
|
|||||||
... |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
через IAT; т.е. если транслятор |
|||
|
|
|
|
|
|
|
|
|
|
|
|
|
по адресу |
|
||||
.rdata |
|
|
|
|
|
|
|
|
|
|
|
|
|
ImageBaseAddress |
|
располагает прототипом |
||
10002000: |
|
74 |
24 |
00 |
00 |
58 |
24 |
00 |
00 |
|
|
|
|
|
|
|||
|
DLL |
void |
|
|
||||||||||||||
... |
|
|
|
|
|
|
|
|
|
|
|
|
|
10000000 |
|
|
||
|
|
|
10002078: |
|
56 |
22 |
00 |
00 |
2E |
23 |
00 |
00 |
|
__declspec(dllimport) |
||||
|
|
|
10002080: |
|
40 |
22 |
00 |
00 |
00 |
00 |
00 |
00 |
|
+000021F4 |
импортируемой |
func(void); |
|
|
... |
|
|
|
|
|
|
|
|
|
|
|
|
|
100021F4 |
|
|||
100020A0: |
% |
d |
00 |
00 |
00 |
00 |
00 |
00 |
|
(подраздел ILT) |
|
то будет сгенерована инструкция |
||||||
... |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
косвенного вызова |
|
||
10002170: FE |
FF |
FF FF |
0B |
16 |
00 |
10 |
|
10000000 |
|
|
||||||||
|
call dword ptr [IAT_func] |
|||||||||||||||||
10002178: |
|
|
|
1F |
16 |
00 |
10 |
|
|
|
|
|
|
|||||
|
|
|
F4 |
21 |
00 |
00 |
|
|
||||||||||
10002180: |
|
|
|
|
00 |
00 |
00 |
00 |
00 |
00 |
00 |
00 |
|
+0000224A |
|
В противном случае транслятор |
||
10002188: |
|
|
|
|
4A |
22 |
00 |
00 |
3C |
20 |
00 |
00 |
|
1000224A |
|
использует прямую адресацию, т.е. |
||
10002190: |
|
|
|
B8 |
21 |
00 |
00 |
00 |
00 |
00 |
00 |
|
|
|||||
10002198: |
|
|
|
00 |
00 |
00 |
00 |
A6 |
24 |
00 |
00 |
|
(имя библиотеки) |
если транслятор располагает |
||||
100021C0: |
|
|
44 |
24 |
00 |
00 |
30 |
24 |
00 |
00 |
|
|
каждой |
func(void); |
|
|||
100021A0: |
|
|
00 |
20 |
00 |
00 |
00 |
00 |
00 |
00 |
|
10000000 |
|
прототипом |
|
|||
... |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||
100021B8: |
|
74 |
24 |
00 |
00 |
58 |
24 |
00 |
00 |
|
+0000203C |
|
void |
|
|
|||
... |
|
|
|
|
|
|
|
|
|
|
|
|
|
1000203C |
Для |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
то будет использована инструкция |
||||||
100021F0: |
|
00 |
00 |
00 |
00 |
26 |
23 |
00 |
00 |
|
(подраздел IAT) |
|||||||
100021F8: |
|
18 |
23 |
00 |
00 |
38 |
23 |
00 |
00 |
|
|
|
call func |
|
||||
10002200: |
|
52 |
23 |
00 |
00 |
0E |
23 |
00 |
00 |
|
|
|
Если позже при сборке выяснится, |
|||||
... |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|||
10002238: |
|
|
|
40 |
22 |
00 |
00 |
00 |
00 |
00 |
00 |
|
+10000000 |
|
что символ импортирован из DLL, то |
|||
10002240: |
|
|
|
|
|
|
|
|
|
|
|
|
||||||
|
|
|
2E |
05 |
p |
r |
i |
n |
t |
f |
|
|||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
00002240 |
|
линкер сгенерирует промежуточные |
||
10002248: 00 |
00 |
M |
S |
V |
C |
R |
9 |
|
10002240 |
|
заглушки (stub), содержащие |
|||||||
10002250: |
|
0 |
. |
d |
l |
l |
00 |
6A 01 |
|
|||||||||
... |
|
|
|
|
|
|
|
|
|
|
K |
E |
|
|
инструкции косвенного перехода; т.е. |
|||
100024A0: 65 |
73 |
65 |
6E |
74 |
00 |
|
|
|||||||||||
100024A8: |
|
|
|
R |
N |
E |
L |
3 |
2 |
. |
d |
|
|
call func |
|
|||
100024B0: |
|
|
|
l |
l |
00 |
00 |
00 |
00 |
00 |
00 |
|
10000000 |
|
будет модифицирован как: |
|||
100024B8: |
|
00 |
00 |
00 |
00 |
00 |
00 |
00 |
00 |
|
|
call __autostub_func |
||||||
100024C0: |
|
00 |
00 |
00 |
00 |
93 |
F0 |
14 |
4B |
|
+000024FC |
|
... |
|
|
|||
100024C8: |
|
00 |
00 |
00 |
00 |
FC 24 |
00 |
00 |
|
100024FC |
|
|
|
|||||
100024D0: |
|
01 |
00 |
00 |
00 |
02 |
00 |
00 |
00 |
|
|
__autostub_func: |
||||||
|
|
(имя библиотеки) |
||||||||||||||||
100024D8: |
|
02 |
00 |
00 |
00 |
E8 |
24 |
00 |
00 |
|
jmp dword ptr [IAT_func] |
|||||||
|
|
|
|
|||||||||||||||
100024E0: |
|
|
F0 |
24 |
00 |
00 |
F8 |
24 |
00 |
00 |
|
список адресов |
|
См. вызов printf по адресу 1000101B; |
||||
100024E8: |
|
|
00 |
10 |
00 |
00 |
10 |
10 |
00 |
00 |
|
|
||||||
100024F0: |
|
|
03 |
25 |
00 |
00 |
09 |
25 |
00 |
00 |
|
список имен |
|
Обращение к экспортируемым |
||||
100024F8: |
|
|
00 |
00 |
01 |
00 |
q |
q |
. |
d |
|
|
||||||
10002500: |
|
|
|
|
l |
l |
00 |
a |
d |
d |
_ |
x |
|
|
|
данным возможно только если они |
||
10002508: |
|
|
00 |
s |
h |
o |
w |
_ |
x 00 |
|
|
|
описаны с «dllimport». |
|||||
... |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|||
.data |
|
|
|
|
FF |
FF FF |
FF FF |
FF |
FF |
|
|
Отдельные сведения о |
||||||
10003000: FF |
|
|
перемещаемых записях: |
|||||||||||||||
10003008: 4E |
E6 |
40 |
BB |
B1 |
19 |
BF |
44 |
|
|
|
||||||||
|
|
|
BASE RELOCATIONS #4 |
|
||||||||||||||
10003010: |
|
|
00 |
00 |
00 |
00 |
00 |
00 |
00 |
00 |
|
|
|
|
||||
|
|
|
|
|
1000 RVA, |
110 SizeOfBlock |
||||||||||||
... |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|||
.reloc |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
HIGHLOW |
10003010 |
|
10004000: |
|
|
00 |
10 |
00 |
00 |
10 |
01 |
00 |
00 |
|
|
|
A |
HIGHLOW |
10003010 |
||
|
|
|
|
|
17 |
HIGHLOW |
100020A0 |
|||||||||||
10004008: |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||||
01 |
30 |
0A |
30 |
11 |
30 |
17 |
30 |
|
|
|
||||||||
... |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
... |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||
10004108: B7 |
38 |
BE 38 |
C6 |
38 |
00 |
00 |
|
|
|
0 |
ABS |
|
||||||
10004110: 00 |
20 |
00 |
00 |
20 |
00 |
00 |
00 |
|
|
|
2000 RVA, |
20 SizeOfBlock |
||||||
10004118: 94 |
30 |
A8 |
30 |
AC 30 |
EC |
30 |
|
|
|
94 |
HIGHLOW |
1000102A |
||||||
Экспорт, импорт, перемещаемые записи в Posix |
каждая запись |
.dynsym |
|
|
|
|
|
|
|
+0000025c (.dynstr) |
Вызов функции, импортируемой из |
||||||||||
Дизассембер секции .plt |
|
|
|
определения символа |
01bc... |
2b |
00 |
00 |
00 |
00 |
00 |
00 |
00 |
«разделяемого объекта» (shared |
|||||||
__loader__@plt: |
|
|
|
|
занимает 16 байт, |
01c4 |
00 |
00 |
00 |
00 |
20 |
00 |
00 |
00 |
0000002b |
object), осуществляется обращением |
|||||
|
pushl |
0x4(%ebx) |
|
|
|
приведена запись с ... |
|
|
|
|
|
|
|
|
00000287 + LoadAddr |
к созданной сборщиком заглушке в |
|||||
|
|
|
|
|
индексом 2 |
.dynstr |
|
|
|
|
|
|
|
|
PLT (Procedure Linkage Table): |
||||||
|
jmp |
*0x8(%ebx) |
|
# загрузчик LD.SO |
_ |
_ |
g |
m |
o |
n |
_ |
|
|||||||||
|
|
Формат записей |
025c |
00 |
|
|
|
|
|||||||||||||
|
.long |
0 |
|
|
|
|
|
|
call |
add_x@plt |
|
||||||||||
|
|
|
|
|
|
0264 |
s |
t |
a |
r |
t |
_ |
_ 00 |
тип перемещаемой |
|
||||||
|
|
|
|
|
|
|
.dynsym и .symtab; ... |
|
|
|
|
|
|
|
|
где |
|
|
|||
__gmon_start__@plt: |
|
|
|
|
|
(имя-значение- |
0284 |
z |
e 00 |
_ |
J |
v |
_ |
R |
записи |
|
|
||||
|
jmp |
*0xc(%ebx) |
|
|
|
|
размер-флаги- |
028c |
e |
g |
i |
s |
t |
e |
r |
C |
02: R_386_PC32 |
add_x@plt: |
Заменяется на |
||
|
pushl |
$0x0 |
|
|
|
|
|
секция) |
0294 |
l |
a |
s |
s |
e |
s 00 |
a |
(отн. адрес символа #) |
jmp |
|
реальный адрес |
|
|
|
|
|
|
|
|
... |
|
|
|
|
|
|
|
|
06: R_386_GLOB_DAT |
*GOT.PLT[add_x] |
||||
|
jmp |
__loader__@plt |
|
|
|
|
.rel.dyn |
|
|
|
|
|
|
|
push |
off_in_rel.plt |
|||||
|
|
|
|
адрес |
|
|
|
|
|
|
|
(адрес символа #) |
|||||||||
__cxa_finalize@plt: |
|
|
|
|
перемещаемой |
... |
|
|
|
|
|
|
|
|
07: R_386_JUMP_SLOT |
jmp |
__loader__@plt |
||||
|
|
|
|
0350 |
08 |
20 |
00 |
00 |
08 |
00 |
00 |
00 |
|||||||||
|
|
|
|
(адрес записи в .plt для #) |
.. |
|
|
||||||||||||||
|
jmp |
*0x10(%ebx) |
|
|
|
|
записи |
0358 |
d4 |
04 |
00 |
00 |
02 |
03 |
00 |
00 |
08: R_386_RELATIVE |
|
|
||
|
pushl |
$0x8 |
|
|
|
|
|
|
0360 |
e8 |
1f |
00 |
00 |
06 |
01 |
00 |
00 |
(прибавить адрес загрузки) __loader__@plt: |
|
||
|
|
|
|
|
|
|
0368 |
ec 1f 00 |
00 |
06 |
02 |
00 |
00 |
|
pushl GOT.PLT+4 (LoadAddr) |
||||||
|
jmp |
__loader__@plt |
|
|
|
|
|
||||||||||||||
|
|
|
|
|
0370 |
f0 |
1f |
00 |
00 |
06 |
04 |
00 |
00 |
индекс символа |
|||||||
|
|
|
|
|
jmp |
*GOT.PLT+8 |
|
||||||||||||||
|
|
|
|
|
|
|
|
|
.rel.plt |
|
|
|
|
|
|
|
|
||||
Дизассемблер начала секции .init |
|
|
|
|
|
|
|
|
|
|
|
в .dynsym |
сборщик создает по одной записи в |
||||||||
|
|
|
|
0378 |
00 |
20 |
00 |
00 |
07 |
01 |
00 |
00 |
|||||||||
|
push |
%ebp |
|
|
|
|
|
|
0380 |
04 |
20 |
00 |
00 |
07 |
04 |
00 |
00 |
|
PLT на каждую импортируемую |
||
|
mov |
%esp,%ebp |
|
|
|
|
|
.init |
|
|
|
|
|
|
|
|
|
||||
|
|
|
|
|
|
55 |
89 |
e5 |
53 |
83 |
ec 04 e8 |
|
функцию и инициализирует |
||||||||
|
push |
%ebx |
|
|
|
|
|
|
0388 |
|
указатель в GOT (Global Offset Table) |
||||||||||
|
sub |
$0x4,%esp |
|
|
|
|
|
... |
|
|
|
|
|
|
|
|
|
||||
|
|
|
|
|
|
.plt |
|
|
|
|
|
|
|
|
|
адресом этой заглушки + 6 — с этого |
|||||
|
call |
1f |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||||
|
|
|
|
__gmon_start__@plt |
03b8 |
ff b3 04 |
00 |
00 |
00 |
ff a3 |
Procedure Linkage Table |
места размещен вызов загрузчика |
|||||||||
1: |
pop |
%ebx |
|
|
|
03c0 |
08 |
00 |
00 |
00 |
00 |
00 |
00 |
00 |
|||||||
|
|
|
|
|
|
16 байт на каждую |
данного символа. |
|
|||||||||||||
|
add |
$0x1c60,%ebx |
# ebx = 1FF4 |
|
03c8 |
ff a3 0c |
00 |
00 |
00 |
68 |
00 |
|
|||||||||
|
|
03d0 |
00 |
00 |
00 |
e9 |
e0 |
ff ff ff |
импортируемую функцию |
GOT.PLT[add_x]: |
|
||||||||||
|
... |
|
|
|
|
|
|
|
|
||||||||||||
|
|
|
|
|
__gmon_start__@plt + 6 |
03d8 |
ff a3 10 |
00 |
00 |
00 |
68 |
08 |
|
||||||||
Частичный дизассемблер секции .text |
03e0 |
00 |
00 |
00 |
e9 |
d0 |
ff ff ff |
|
.long |
add_x@plt+6 |
|
||||||||||
|
|
|
.text |
|
|
|
|
|
|
|
|
|
который заменяется загрузчиком на |
||||||||
add_x: |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Величина -4 (0xFFFFFFFC) |
||||
mov |
0x4(%esp),%eax |
|
|
|
|
03f0 |
55 |
89 |
e5 |
56 |
53 |
e8 |
ad 00 |
.long |
real_address |
||||||
|
|
|
|
|
... |
d2 |
83 |
c4 |
04 |
5b |
5d |
c3 |
8b |
указывает смещение адреса |
|||||||
|
add |
0x2014,%eax |
|
|
|
|
|
04a0 |
перемещаемой записи |
Во время загрузки исполняемого |
|||||||||||
|
|
|
|
|
|
04a8 |
1c |
24 |
c3 |
90 |
90 |
90 |
90 |
90 |
относительно EIP, |
||||||
# 4b6: |
R_386_RELATIVE |
|
*ABS* |
|
|
|
04b0 |
8b |
44 |
24 |
04 |
03 |
05 |
14 |
20 |
используемого инструкцией |
файла загрузчик сразу |
|
|||
|
mov |
%eax,0x2014 |
|
|
|
|
|
04b8 |
00 |
00 |
a3 |
14 |
20 |
00 |
00 |
c3 |
|
модифицирует первые записи в |
|||
|
|
|
|
|
|
04c0 |
83 |
ec 0c |
a1 |
14 |
20 |
00 |
00 |
|
|||||||
# 4bb: |
R_386_RELATIVE |
|
*ABS* |
|
|
|
Адрес |
.got.plt так, что бы стало |
|||||||||||||
|
|
|
|
04c8 |
c7 |
04 |
24 |
34 |
05 |
00 |
00 |
89 |
|||||||||
|
ret |
|
|
|
|
|
|
|
04d0 |
44 |
24 |
04 |
e8 |
fc ff ff ff |
загрузки |
возможно обращение к |
|
||||
show_x: |
|
|
|
|
|
|
|
|
04d8 |
83 |
c4 |
0c |
c3 |
90 |
90 |
90 |
90 |
этого . |
__loader__@plt из загруженного |
||
sub |
$0xc,%esp |
|
|
|
|
|
... |
|
|
|
|
|
|
|
|
|
|||||
|
|
|
|
|
|
.fini |
|
|
|
|
|
|
|
|
|
модуля. |
|
|
|||
|
mov |
0x2014,%eax |
|
|
|
|
|
0518 |
55 |
89 |
e5 |
53 |
83 |
ec 04 e8 |
Global Offset Table |
Импорт данных специфичен: в |
|||||
# 4c4: |
R_386_RELATIVE |
|
*ABS* |
|
|
|
... |
|
|
|
|
|
|
|
|
4 байта на каждый символ |
разделяемом объекте обращения к |
||||
|
|
Смещение |
.got |
|
|
|
|
|
|
|
|
||||||||||
|
movl |
$0x534,(%esp) |
|
|
|
|
|
|
|
|
|
|
(типично, если .rel |
экспортируемым данным |
|
||||||
|
|
|
1fe8 |
00 |
00 |
00 |
00 |
00 |
00 |
00 |
00 |
|
|||||||||
# 4cb: |
R_386_RELATIVE |
|
*ABS* |
|
секции .dynamic |
1ff0 |
00 |
00 |
00 |
00 |
|
|
|
|
ссылается на записи в .got) описываются со специфичным типом |
||||||
|
mov |
%eax,0x4(%esp) |
|
|
|
|
.got.plt |
1f |
00 |
00 |
00 |
00 |
00 |
00 |
LoadAddr |
перемещаемой записи R_386_COPY, |
|||||
|
call |
.+1 |
|
|
|
|
|
EBX → 1ff4 |
10 |
+000003CE |
а в приложении, ссылающемся на на |
||||||||||
# 4d4: |
printf |
|
|
Адрес |
1ffc |
00 |
00 |
00 |
00 |
ce 03 00 00 |
|||||||||||
R_386_PC32 |
|
|
2004 |
de 03 00 |
00 |
|
|
|
|
__gmon_start__@plt+6 |
эти данные, создается их копия; |
||||||||||
|
add |
$0xc,%esp |
|
|
|
процедуры |
.data |
08 |
20 |
00 |
00 |
|
|
|
|
Адрес замещается загрузчиком |
после чего корректируются все |
||||
|
ret |
|
|
|
|
|
загрузки в |
2008 |
|
|
|
|
|
перемещаемые записи библиотеки |
|||||||
|
|
|
|
|
|
.bss |
|
|
|
|
|
|
|
|
__cxa_finalize@plt+6, |
||||||
В приведенном примере обращение к функции |
|
LD.SO |
00 |
00 |
00 |
00 |
00 |
00 |
00 |
00 |
так, что бы |
использовался |
|
||||||||
printf из стандартной libc выполнено прямым вызовом. |
|
200c |
замещаемый на реальный |
экземпляр данных в приложении. |
|||||||||||||||||
|
2014 |
00 |
00 |
00 |
00 |
|
|
|
|
||||||||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
адрес процедуры |
|
|
|
POSIX. Позиционно-независимый код в архитектуре IA-32.
Использование перемещаемых записей несколько замедляет процесс загрузки разделяемых объектов и, кроме того, существенно осложняет использование общих проекций — в современных POSIX-системах часто варьируют адреса разделяемых объектов от процесса к процессу и от запуска к запуску; это существенно усложняет многие виды атак, особенно удаленных.
С этим связана рекомендация использовать позиционно-независимый код при компиляции разделяемых объектов, несмотря даже на то, что код получается большего размера и чуть медленнее выполняется (усложняется только обращение к статическим данным; работа с автоматическими переменными остается без изменений).
Пример реализации позиционно-независимого кода:
|
Исходный код test.c |
|
|
gcc -S -o test-rel.s -O3 -fomit-frame-pointer -shared test.c |
|
|
gcc -fPIC -S -o test-rel.s -O3 -fomit-frame-pointer -shared test.c |
|
|||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include <stdio.h> |
.section |
.rodata.str1.1,"aMS" |
.section |
.rodata.str1.1,"aMS" |
|
|||||||
|
static int s_x; |
|
|
.LC0: .string"%d" |
|
|
|
.LC0: .string"%d" |
|
||||
|
|
|
.text |
|
|
|
|
.text |
|
|
|
||
|
|
|
|
|
|
|
|
|
|
|
|
||
|
void show_x( void ) |
|
|
.globl add_x |
|
|
|
|
.globl add_x |
|
|
|
|
|
|
|
.type |
add_x, @function |
|
|
.type |
add_x, @function |
|
||||
|
{ |
|
|
|
|
|
|
||||||
|
|
|
|
add_x: |
|
|
|
|
add_x: |
|
|
|
|
|
printf("%d", add_x(0)); |
|
|
|
|
|
|
|
|
|
|||
|
|
|
movl |
4(%esp), %eax |
|
|
call |
__i686.get_pc_thunk.cx |
|
||||
|
} |
|
|
|
|
|
|
||||||
|
|
|
|
addl |
s_x, %eax |
|
|
addl |
$_GLOBAL_OFFSET_TABLE_, %ecx |
|
|||
|
|
|
|
|
|
|
|
||||||
|
int add_x( int v ) |
|
|
movl |
%eax, s_x |
|
|
movl |
4(%esp), %eax |
|
|||
|
|
|
ret |
|
|
|
|
addl |
s_x@GOTOFF(%ecx), %eax |
|
|||
|
{ |
|
|
|
|
|
|
|
|
||||
|
|
|
|
.globl show_x |
|
|
|
|
movl |
%eax, s_x@GOTOFF(%ecx) |
|
||
|
return s_x += v; |
|
|
|
|
|
|
|
|||||
|
|
|
|
|
|
|
ret |
|
|
|
|||
|
} |
|
|
|
.type |
show_x, @function |
|
|
|
|
|
||
|
|
|
|
|
|
|
|
|
|
||||
|
|
|
|
|
show_x: |
|
|
|
|
.globl show_x |
|
|
|
|
|
|
|
|
|
|
|
||||||
|
Получение адреса секции данных |
|
|
|
|
|
|
|
|
|
|||
|
|
|
subl |
$12, %esp |
|
|
.type |
show_x, @function |
|
||||
|
осуществляется с помощью вызова |
|
|
movl |
s_x, %eax |
|
|
show_x: |
|
|
|
||
|
служебной процедуры, загружающей в |
|
|
movl |
$.LC0, (%esp) |
|
|
subl |
$8, %esp |
|
|||
|
какой-либо регистр значение адреса |
|
|
movl |
%eax, 4(%esp) |
|
|
movl |
$0, (%esp) |
|
|||
|
возврата. |
|
|
|
call |
printf |
|
|
|
call |
add_x@PLT |
|
|
|
Вызов __i686.get_pc_thunk.cx |
|
|
addl |
$12, %esp |
|
|
call |
__i686.get_pc_thunk.cx |
|
|||
|
возвращает в ecx адрес возврата — т.е. |
|
|
ret |
|
|
|
|
addl |
$_GLOBAL_OFFSET_TABLE_, %ecx |
|
||
|
адрес следующей после вызова |
|
|
.local s_x |
|
|
|
movl |
%eax, 4(%esp) |
|
|||
|
инструкции; далее сборщик может |
|
|
|
|
|
leal |
.LC0@GOTOFF(%ecx), %eax |
|
||||
|
|
|
.comm |
s_x,4,4 |
|
|
|
|
|||||
|
вычислить расстояние между текущей |
|
|
|
|
|
movl |
%eax, (%esp) |
|
||||
|
|
|
|
|
|
|
|
|
|||||
|
|
|
|
|
|
|
|
|
|
call |
printf@PLT |
|
|
|
точкой и началом секции данных (реально — начала секции .got.plt, после которой |
|
|
|
|||||||||
|
|
|
addl |
$8, %esp |
|
||||||||
|
размещаются секции .data и .bss). Т.е. примерно такие инструкции: |
|
|
|
|||||||||
|
|
|
ret |
|
|
|
|||||||
|
call |
__i686.get_pc_thunk.cx |
|
|
|
|
|
|
|
||||
|
|
|
|
|
.local |
s_x |
|
|
|||||
|
addl |
$адрес_секции_got - ., %ecx |
|
|
|
|
|
|
|||||
|
Компилятор gcc распознает обращение к специальной «переменной» _GLOBAL_OFFSET_TABLE_ |
|
|
.comm |
s_x,4,4 |
|
|||||||
|
|
|
|
|
|
|
|||||||
|
как необходимость вычислить расстояние до секции .got.plt. |
|
|
|
.section |
.text.__i686.get_pc_thunk.cx,"axG" |
|
||||||
|
Функции семейства ...get_pc_thunk... генерируются компилятором и размещаются в |
|
|
.globl __i686.get_pc_thunk.cx |
|
||||||||
|
специфичных секциях по мере надобности. Так, например, функция __i686.get_pc_thunk.bx |
|
|
.hidden__i686.get_pc_thunk.cx |
|
||||||||
|
вернет значение EIP в EBX, а не в ECX и будет размещена в отдельной секции — это позволит |
|
|
.type |
__i686.get_pc_thunk.cx, @function |
|
|||||||
|
сборщику наложить одноименные секции с соответствующими процедурами друг на друга. |
|
|
__i686.get_pc_thunk.cx: |
|
||||||||
|
|
|
movl |
(%esp), %ecx |
|
||||||||
|
|
|
|
|
|
|
|
|
|
|
|||
|
|
|
|
|
|
|
|
|
|
ret |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
