МЕНЮ

Язык СИ с нуля. История появления. Уроки для начинающих безопасниковСамый базовый и основной язык на котором строится весь современный мир программного обеспечения – это язык Си. И конечно же, раз речь заходит о программном обеспечении, тут сразу всплывает вопрос уязвимостей в СИшном софте. Любой мало-мальски грамотный специалист по информационной безопасности должен представлять откуда растут ноги у этой истории, как что работает и всё такое. Zip File, мамкины хаЦкеры. С вами Денчик и сегодня мы рассмотрим такие краеугольные вещи, как машинный код, ассемблер, и также поговорим об особенностях высокоуровневых языков программирования. Само собой преимущественно речь будет идти о языке С. Ну а уже затем, базируясь на полученных знаниях мы разберёмся с основными видами уязвимостей, встречающихся в программном обеспечении. Если интересна данная тема, тогда устраивайтесь по удобней, наливайте себе чайку по забористее и будем вместе погружаться в интереснейший мир программирования на самом популярном языке среди рождённых до пришествия к власти дяди Володи. Погнали.

Начнём с самого простого. Машинного кода и языка Ассемблер. Сразу оговорюсь, что материал, который будет представлен следующие 10 минут будет довольно душным.

Но запоминать его досконально от вас и не требуется. Достаточно понять общие ключевые идеи, а конкретные команды и их значение – оставьте лупоглазым программерам.

Нам же, как хаЦкерам, важна сама суть. Однако, если вам всё же хочется разобраться во всём досканально, то позаботьтесь о том, чтобы в вашем распоряжении была машинка на Линуксе. Лучше всего использовать Дебиан. 

Накатите на неё несколько инструментов и не забудьте об удобной среде для редактирования кода. Хотя, если вам, как и мне кристалически по**ую где писать – можете использовать Vim.

Машинный код 

Окей. С тем, что вам понадобится для освоения, разобрались. Теперь к сути. Вы наверняка в курсе что сердцем любого компьютера является процессор. Это такой чип, который умеет исполнять команды или как их ещё называют – инструкции процессора.

Соответственно исполнение этих инструкций – это исполнение программ. Т.к. современные процессоры имеют несколько ядер – каждое ядро отвечает за исполнение своего набора инструкций в параллели.

Таким образом несколько запущенных программ могут работать на одном компьютере одновременно. До того, как появились многоядерные процессоры наш чип метался от одного процесса к другому и порой очевидно не вывозил.

Но благо, прогресс не стоит на месте и многоядерность плотно вошла в нашу жизнь. Параллельно с тем, что процессор обрабатывает инструкции – он получает какие-то данные из регистров. 

Так называемой быстрой памяти, расположенной на самом чипе. Также можно взять необходимые данные из оперативно-запоминающего устройства. Да, так уж вышло, что напрямую с дисков хранения HDD и SSD данные проц не читает.

Нужна прокладка через оперативу или кэш-чипа. Т.е. любое видео Денчика, которое вы смотрите на ютубе, любой супер-секретный парольчик, который вы вводите сёрфя в Даркнете сначала попадает в оперативу и только потом доходит до проца. 

В теории, при выключении компьютера вся оперативная память стирается. Но это лишь в теории. На практике же остаточная намагниченность сохраняется. 

А это значит, что некоторые данные из неё всё же доступны для чтения даже при выключенной машине.

Такие дела малята. Соответственно помимо оперативы данные могут хранится на различного рода хранилищах и на сетке. Вам важно запомнить, что любая программа состоит из машинных инструкций. Что на процессоре есть регистры и над ним есть какая-то физическая память.

Ассемблер

Окей. С этим разобрались. Теперь подробнее углубимся в машинный код. Процессор умеет исполнять команды, закодированные в специальном коде.

Это набор байт, который умеет декодировать процессор для выполнения операций. Среди которых выгрузка данных из ОЗУ, запись данных из процессора в ОЗУ, сложение, вычитание и другие безумно важные операции. 

Чтобы нам, как спецам из мира IT не нужно было выполнять работу процессора. Т.е. кодировать и декодировать биты и байты вручную, это ведь неибаца, как сложно, умные дядьки придумали специальные мнемоники.

Т.е. конструкции позволяющие записывать программы в виде текста, а затем переводить это дело в машинный код посредством ассемблера. А все языки, которые могут это делать, попутно стали именовать языками ассемблера.

Ассемблер от английского – собиратель. Следовательно, он берёт из текстового файлика и собирает исполняемую программу. На практике, конечно, процесс выглядит чуть сложнее, но сама логика от этого не меняется.

Языков Ассемблера достаточно много. Есть разная процессорная архитектура. Интеловские x86 и 64, дофига и больше версий arm. Есть архитектура PowerPC используемая когда-то в компьютерах Apple.

К слову именно процессорная архитектура определяет регистры, инструкции и прочие вещи связанные с процессором. Вот вам пример, написанный на языке Ассемблера в синтаксисе ЭйтиЭнТи.

В данном конкретном случае с помощью системных вызовов программа из пользовательского окружения добирается до окружения ядра, чтобы выполнить какие-то интересные вещи. 

И всё вроде бы хорошо. Однако главная проблема Ассемблера заключается в том, что инструкции и регистры очень большие и сложные. Лично я в живую видел инструкции для процессоров Intel и это такой огромный трёхтомник.

Само собой все их выучить невозможно, а каждый раз гуглить или рыться в справочнике конкретно так заколёбывает. Соответственно если вы пишите нечто большее, чем фразу Hello World в чёрной консоли, то будьте готовы страдать. 

Чтобы обойти эту проблему британские учёные начали создавать разноуровневые языки программирования. В данном случае речь идёт об уровнях абстракции над вашим железом.

Т.е. самый низкоуровневый язык – это язык Ассемблера. Потому что он работает напрямую с процессорной архитектурой.

Языки, находящиеся на более высших уровнях уже, абстрагируют такие вещи, как регистры, память и позволяют работать с железом не напрямую, а с помощью указателей.

В самых высокоуровневых языках работать с железом напрямую уже в принципе невозможно. Порой вы даже самого программирования толком увидеть не сможете.

Так в создании скриптов на Bash’е или PowerShell’е его реально по минимуму. Вы в принципе пишете, не задумываясь о том, как это дело там дальше работает под капотом. 

Язык C

Язык C появился 70-х годах в момент создания операционной системы Unix. Собственно, его и создали для того, чтобы переписать код данной системы с Ассемблера на что-то более адекватное.

Ключевые идеи заключаются в выжимании максимальной производительности при минимальной ресурсоёмкости и достаточно высоком по сравнению с Ассемблером уровне абстракции. 

Ну и на всякий случай всегда остаётся возможность низкоуровневого доступа и выполнение потенциально небезопасных операций за счёт практически полной свободы действий предоставленной разработчику. 

Т.е. раньше подразумевалось, что программист точно знает, что делает. Сейчас же, благодаря нереальной абстракции, вы можете писать сайты, создавать приложения и прочие полезные вещи буквально со школьной скамьи.

Но в те далёкие времена дело обстояло иначе и программистами становились только исключительно умный дядьки. Они в свою очередь и писали на С ядра самых популярных систем (Windows, Linux, BSD).

Создавали системные библиотеки CRT, Glibc. Ваяли веб-сервера nginx и apache. База данных PostgresSQL это тоже СИшная тема. Криптографическая утилита OpenSSL, сервис OpenSSH.

А уж про интерпретаторы и компиляторы для PHP и Python я вообще молчу. В основе всех этих дико популярных вещей лежит Си. К тому же, без этого языка не было бы всеми любимого, а кем-то наоборот ненавистного C++.

С++ это не просто какое-то расширение или дополнение. Это совершенно новый язык программирования, который стоит над языком С и невероятно расширяет его возможности.

Он присутствует в большом количестве других популярных продуктов – например в той же, Java. Поэтому ключевые особенности (включая типичные ошибки, ведущие к уязвимостям) так или иначе отражаются на всех прогах, которые как-то с ним связаны.

Это не хорошо и не плохо. Просто такая данность. Порой синтаксис C++ усложняется настолько, что и Ассемблер уже не кажется такой жестью. Общая сложность конструкций в нём уж точно значительно проще.

А ещё проще, не разменивать своё время даром на изучение всех известных языков программирования, а подготовить себе базу в виде подушки безопасности, которая точно пригодится вам независимо от выбора языка.

И да, как вы уже догадались, речь сейчас о моём авторском курсе, ориентированном на начинающих программистов и людей, занимающихся разработкой, с бодрым названием «GIT-это просто!»

Для его создания я нанял стороннего специалиста по данной теме и в тандеме у нас получилось сделать не просто качественный и весёлый, а суперполезный продукт, изучив который вы приобретёте в копилку скилл востребованный в любой IT-ветке.

Если ты начинающий или более-менее опытный разработчик, сисадмин занимающийся скриптами или безопасник помешанный на автоматизации – эта темка точно тебе зайдёт. 

Ссылку на практический курс «GIT – Это просто!» и на другие авторские материалы от Денчика ищи в описании. Поддержи канал вкинув пару косых. И я непременно отблагодарю тебя новой порцией полезнейших знаний по полной программе.

Типичная схема ПО

Типичная схема программного обеспечения выглядит следующий образом. Не дне стека у нас железо. В том числе микропрограммы, встроенные в чипы для управления этим самым железом. Привет BIOS и UEFI.

Над железом стоит ядро операционной системы, написанное на языке C. В этой операционной системе находятся библиотеки для программ, написанные на нём же.

Системные библиотеки, отвечающие за отрисовку графики, управление сервисами и службами, работу с драйверами и т.д. Над этим делом находится какая-нибудь платформа. 

Представляющая из себя набор инструментов и библиотек необходимых для того, чтобы работали программы, написанные на соответствующих языках. JVM, .NET, PHP, Phyton и прочие знакомые каждому вещи.

Дальше эти платформы используют какие-то внешние библиотеки с чужим кодом и только в самом конце располагается ваша мега-программа, которая представляет собой сайт с бодрой порнухой или приложение для знакомств с меньшинствами.

Но давайте отбросим шутеечки в сторону и поговорим о проблеме. А она, как вы сами понимаете никуда не ушла. Даже в самой супер-пупер крутой программе всегда найдётся несколько багов. 

В библиотеках, которые ею используются. В платформе. В системных библиотеках. Ну и далее ниже по списку. На любом из этих этапов можно нарыть уязвимость и попытаться нагнуть конечную разработку.

Баги встречаются даже в софте железа. Если его своевременно не обновлять, можно словить под дых. Например, очень показательна была история с Meltdown и Spectre. 

Из-за особенностей архитектуры современных процессоров, которые допускают спекулятивные исполнения инструкций. 

Говоря простым языком, изначально процессоры запрашивая инструкции из памяти – должны дождаться их исполнения.

Однако современные процессоры очень быстрые и могут начать читать следующие инструкции, ожидая, что вы запросите из памяти какое-то конкретное значение. По сути, работают на опережение.

Упрощая для пятиклассников – это когда вы 100500 раз гоняли одну и ту же песню Моргена во Вконтакте, на 100501 раз компьютер уже знает, что вы дурачок и скорее всего включите её снова. 

Так взломщик может написать программу, которая с помощью перебора может воспользоваться этой спекулятивной особенностью процессоров и вытащить данные из памяти, которая хакеру по умолчанию не доступна.

Например, вы заходите на сайт. У вас открывается отдельная вкладка. На ней исполняется JavaScript. Исполнение возможно только в рамках этой конкретной вкладки. 

Однако данные из неё затем можно сопоставить с другими сайтами и в случае совпадения – поработать уже более пристально.

Так у вас может совпадать связка логина и пароля, адрес почты, проживания, да бог весть чего ещё. Если интересно погуглите на досуге историю со скандалом по поводу Meltdown и Spectre. Думаю, что зайдёт. Особенно если вы параноик. 

Окей, друзья. Нынче мы разобрали такие понятия, как машинный код, ассемблер, а также поговорили об особенностях высокоуровневых языков программирования.

Я немножко не подрасчитал свои силы и поэтому практическую часть пришлось перенести на следующий ролик. В нём мы подробнейшим образом рассмотрим проблему хранения данных.

Ситуации, при которых возникает переполнение буфера. Credentials, активацию, Input Validations и ещё кучу всего интересного. 

Так что, если ещё не подписан, не щёлкай **лом и жмякай на колокольчик, дабы не пропустить этот полезнейший движ.

Ну а тех, кто давненько в строю, прошу написать комментарий по поводу того, что бы вы хотели увидеть в ближайших видосах. Я к этим советам, конечно, никогда не прислушиваюсь, но очень кайфово осознавать, что кто-то реально тратит на это свои силы и время. 

С вами, как обычно, был Денчик. В заключении, по традиции, хочу пожелать всем досмотревшим ролик до этой минуты удачи, успеха и самое главное, отличного настроения.

Берегите себя и свои данные, учитесь писать код на нескольких языках, не циклитесь на одной корзине и помните. Диверсификация важна, даже в среде матёрых IT-шников.

Вкладывайте свои силы в изучение самых разных умений и навыков и тогда, вы точно не останетесь без корочки хлеба. До встречи в следующем выпуске, мои кайфные друже. Всем пока.

Не можешь понять, куда делись видео по взломам и хакингу? Они переехали в наш уютный паблик в телеге

telegram chanel

Хочешь больше контента? Подписывайся на YouTube-канал!

Курс «Диплом за неделю»

Пособие «Библия вардрайвинга»

Курс Cisco «CCNA: Introduction to Networks»

© 2024. IT-спец. Денис Курец.