#c #assembly #gcc #glibc #fortify-source
#c #сборка #gcc #glibc #укрепить исходный код
Вопрос:
Недавно я прочитал о D_FORTIFY_SOURCE и изменениях, которые он вносит в уязвимые функции. Я хотел с этим повозиться и поэтому создал небольшой тестовый двоичный файл.
Исходный код тестовых двоичных файлов:
#include <stdio.h>
#include <stdlib.h>
//No ASLR/PIE
//Enable FORTIFY
//
//
//
void shell()
{
system("sh");
}
int flag = 0;
int main(int argc, char * argv[])
{
char buf [256];
fgets(buf, sizeof(buf), stdin);
printf(buf);
if(flag)
{
shell();
}
}
Он не должен был ничего делать, просто для проверки защиты printf.
Однако, когда я компилировал программу, она, похоже, не была «укреплена»
Точная команда gcc была:
gcc fsFORTIFIED.c -o fsFORTIFIED -m32 -no-pie -D_FORITFY_SOURCE=2 -O2
Я убедился, что флаг оптимизации был установлен, но стандартная функция printf осталась. GDB предоставил сборку основного:
0x080491c6 < 0>: lea ecx,[esp 0x4]
0x080491ca < 4>: and esp,0xfffffff0
0x080491cd < 7>: push DWORD PTR [ecx-0x4]
0x080491d0 < 10>: push ebp
0x080491d1 < 11>: mov ebp,esp
0x080491d3 < 13>: push esi
0x080491d4 < 14>: push ebx
0x080491d5 < 15>: push ecx
0x080491d6 < 16>: sub esp,0x120
0x080491dc < 22>: call 0x80490e0 <__x86.get_pc_thunk.bx>
0x080491e1 < 27>: add ebx,0x2e1f
0x080491e7 < 33>: mov eax,gs:0x14
0x080491ed < 39>: mov DWORD PTR [ebp-0x1c],eax
0x080491f0 < 42>: xor eax,eax
0x080491f2 < 44>: mov eax,DWORD PTR [ebx-0x8]
0x080491f8 < 50>: push DWORD PTR [eax]
0x080491fa < 52>: push 0x100
0x080491ff < 57>: lea esi,[ebp-0x11c]
0x08049205 < 63>: push esi
0x08049206 < 64>: call 0x8049050 <fgets@plt>
0x0804920b < 69>: mov DWORD PTR [esp],esi
0x0804920e < 72>: call 0x8049040 <printf@plt>
0x08049213 < 77>: add esp,0x10
0x08049216 < 80>: cmp DWORD PTR [ebx 0x2c],0x0
0x0804921d < 87>: jne 0x804923b <main 117>
0x0804921f < 89>: mov eax,DWORD PTR [ebp-0x1c]
0x08049222 < 92>: sub eax,DWORD PTR gs:0x14
0x08049229 < 99>: jne 0x8049242 <main 124>
0x0804922b < 101>: mov eax,0x0
0x08049230 < 106>: lea esp,[ebp-0xc]
0x08049233 < 109>: pop ecx
0x08049234 < 110>: pop ebx
0x08049235 < 111>: pop esi
0x08049236 < 112>: pop ebp
0x08049237 < 113>: lea esp,[ecx-0x4]
0x0804923a < 116>: ret
0x0804923b < 117>: call 0x80491a6 <shell>
0x08049240 < 122>: jmp 0x804921f <main 89>
0x08049242 < 124>: call 0x80492d0 <__stack_chk_fail_local>
Здесь я ожидал вызова printf_chk@plt, но вместо этого у него был printf@plt .
Чтобы убедиться, я запустил программу и ввел в нее ввод % 3 $ x, и она работала нормально, а не останавливалась.
Мой вопрос в том, почему GCC не реализует должным образом D_FORITFY_SOURCE даже после установки флага оптимизации?
Помощь приветствуется
Комментарии:
1.
D_FORITFY_SOURCE
—>D_FORTIFY_SOURCE
2.Попробуйте сначала
gcc -v
, но прочитайте документацию GCC; возможно, также спросите в спискеgcc-help@gcc.gnu.org
рассылки3. Вы отредактировали команду в своем вопросе, не редактируя код. Вы копировали / вставляли каждый раз, или все еще может быть опечатка в том, что вы на самом деле запускали?
4. @PeterCordes ах, мои извинения. При проверке кажется, что в исходной команде была орфографическая ошибка (я думал, что это было только в этом сообщении), поэтому она не смогла скомпилироваться с проверками. Я не понял, что в gcc не было ошибки из-за неправильного написания флага. Проблема решена. Спасибо за ваше время
5.
-Dfoo=bar
просто определяет макрос препроцессора, точно такой же, как#D_FORTIFY_SOURCE 2
в верхней части вашего файла. Только несколько специальных имен макросов влияют на заголовки, такие как stdio.h. Для таких параметров, как-march=skylake
или что угодно, GCC принимает только допустимые параметры, которые он распознает. Но, конечно-Dfoo=bar
, это действительно для anyfoo
, он просто ничего не делает, потому что это не макрос, который заголовки glibc используют в своих#ifdef
s.
Ответ №1:
Убедитесь -D_FORTIFY_SOURCE=2
, что написано правильно.
(В данном случае это было не так: -D_FORITFY_SOURCE=2
была проблема.)
В отличие от обычных опций, GCC не может обнаружить опечатки в этом для вас.
-Dfoo=bar
просто определяет макрос препроцессора (руководство GCC), точно такой же, как #D_FORTIFY_SOURCE 2
вверху вашего файла. ( -D
это стандартная опция компилятора, которую принимают все компиляторы, а не только GCC.) Только несколько специальных имен макросов влияют на заголовки, такие как stdio.h .
Для таких параметров, как -fstack-protector-strong
-march=skylake
или -fno-math-errno
или что-то еще, GCC принимает только допустимые параметры, которые он распознает. Но, конечно -Dfoo=bar
, это действительно для любого foo, он просто ничего не делает, потому что это не макрос, который заголовки glibc используют в своих #ifdef
s.
-D
Написано правильно; остальная часть параметра — это только то, что определяется.
В ISO C имена глобальной области видимости, начинающиеся с _
1, зарезервированы для использования реализацией, поэтому определение _FORTIFY_SOURCE
может быть специальным. Но сам GCC не отклоняет подобные имена. Чтобы GCC мог это сделать, он должен был бы знать все имена, которые используют внутренние компоненты glibc, MUSL и другие части «реализации C», и это затруднило бы работу с этими заголовками.
Примечание 1: правила зарезервированных имен несколько менее широки, я упрощаю.
Комментарии:
1. Обычно на вопросы об опечатках не интересно отвечать; Я отвечаю, потому что OP был удивлен, что GCC не уловил эту опечатку, которая могла быть предположением, которое могли бы сделать другие будущие читатели.