• XSS.stack #1 – первый литературный журнал от юзеров форума

Статья Реверс-инжиниринг для всех

Часть 21 - Как скомпилировать программу

Давайте еще раз посмотрим на программу C с прошлого модуля и подробнее рассмотрим, как мы превращаем исходный код в исполняемый файл.

11.jpg


Чтобы скомпилировать эту программу на C, мы просто набираем:

12.jpg


Этот единственный шаг создаст exit.o, который является двоичным объектным файлом, и exit, который является двоичным исполняемым файлом.

Если мы хотим преобразовать этот исходный код C в ассемблер, нам нужно использовать компилятор GNU следующим образом. Начнем с выполнения следующей команды в терминале:

13.jpg


Начнем с переключателя -S. Ключ -S создает сопоставимый исходный код синтаксической сборки AT&T. -m32 создаст 32-разрядный исполняемый файл, а -O0 сообщит компилятору, какой объем оптимизации следует использовать при компиляции двоичного файла. Это заглавная буква O и цифра 0. Цифра 0 в этом случае означает отсутствие оптимизации, что означает, что это наиболее удобочитаемый набор инструкций. Если бы вы заменили 1, 2 или 3, объем оптимизации увеличивается по мере увеличения значений.

14.jpg


Этот шаг выше создает exit.s, который является эквивалентным исходным кодом языка ассемблера, как мы упоминали выше.

Затем нам нужно скомпилировать исходный код в двоичный объектный файл, который будет генерировать файл exit.o.

15.jpg


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

16.jpg


Ранее, когда мы исследовали вывод из исполняемого файла в программе под названием objdump и исследовали основную функцию, мы увидели следующее, за исключением того, что на этот раз мы будем использовать синтаксис языка ассемблера AT&T:

17.jpg


Эта команда выше создаст следующий вывод:

18.jpg


Давайте исследуем код в отладчике. Давайте запустим GDB, который является отладчиком GNU, и сначала перечислим исходный код, набрав l, затем установим точку останова на main и запустим программу. Наконец, мы дизассемблируем и рассмотрим вывод ниже:

19.jpg


В каждом из трех вышеуказанных выводов вы, по сути, увидите один и тот же набор инструкций, которые мы более подробно рассмотрим в будущих уроках.

До сих пор на протяжении всей этой серии руководств мы рассматривали язык ассемблера синтаксиса Intel. Мы собираемся сосредоточить наше внимание на синтаксисе AT&T, как я сказал выше, поскольку это естественный синтаксис, используемый в Linux с GNU Assembler и GNU Debugger.

Самая большая разница, которую вы увидите, заключается в том, что в синтаксисе AT&T источник и назначение меняются местами.

Синтаксис AT&T: movl% esp,% ebp [Это означает переместить esp в ebp.]

Синтаксис Intel: mov esp, ebp [Это означает переместить ebp в esp.]

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

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

20.jpg


Чтобы скомпилировать это, мы будем использовать ассемблер GAS и линкер:

21.jpg


Чтобы запустить любой исполняемый файл в Linux, вы вводите ./ и имя исполняемого двоичного файла. В этом случае мы набираем ./exit и нажимаем Энтер. Когда мы это делаем, ничего не происходит. Это хорошо, так как все, что мы сделали, это создали программу, которая выходила бы обратно в ОС.

Я с нетерпением жду встречи с вами в следующем модуле, когда мы углубимся еще больше в код ассемблера!
 
Часть 22 - Программа № 1 [перемещение данных]

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

Мы собираемся создать 32-битные программы, поскольку большинство вредоносных программ написано в 32-битном режиме, чтобы атаковать максимальное количество систем. Имейте в виду, что даже если у ВСЕХ из нас есть 64-битные операционные системы, 32-битные программы могут работать на них.

По большей части, когда дело касается ассемблера, мы работали с синтаксисом Intel, однако я собираюсь сосредоточиться на собственном синтаксисе AT&T в будущем. Как я продемонстрировал в предыдущих руководствах, очень легко преобразовать синтаксис Intel и AT&T туда и обратно.

Каждая программа на ассемблере разделена на три части:

1) Раздел данных: этот раздел используется для объявления инициализированных данных или констант, поскольку эти данные никогда не меняются во время выполнения. Вы можете объявлять постоянные значения, размеры буфера, имена файлов и т.д.

2) Раздел BSS: этот раздел используется для объявления неинициализированных данных или переменных.

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

Критически важным для любого развития является использование комментариев. В синтаксисе AT&T мы используем символ # для объявления комментария, поскольку любые данные после этого символа в соответствующей строке будут игнорироваться компилятором.

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

[метка] мнемоника [операнды] [комментарий]

Базовая инструкция состоит из двух частей, первая из которых - это имя инструкции или мнемоника, которая выполняется, а вторая часть - операнды или параметры команды.

Наша первая программа продемонстрирует, как сразу переместить данные в регистр и сразу данные в память.

Давайте откроем VIM и создадим программу с именем moving_immediate_data.s и введем следующее:

31.jpg


Для компиляции введите:

as –32 -o moving_immediate_data.o moving_immediate_data.s

ld -m elf_i386 -o moving_immediate_data moving_immediate_data.o


Для запуска введите:

./moving_immediate_data

Я также хотел бы показать вам, как это будет выглядеть в синтаксисе Intel. Прежде чем мы рассмотрим эту часть, вам нужно будет ввести sudo apt-get install nasm в командной строке, которая установит Netwide Assembler:

32.jpg


Для компиляции введите:

nasm -f elf32 moving_immediate_data.asm

ld -m elf_i386 -o moving_immediate_data moving_immediate_data.o


Для запуска введите:

./moving_immediate_data

Ладно, вот зе хек :D Вывода нет! Это правильно, и вы не сделали ничего плохого. Многие из наших программ на самом деле ничего не делают, поскольку они не более чем программы-песочницы, которые мы будем использовать в GDB для анализа и манипуляции.

В следующем модуле мы погрузимся в отладчик GNU GDB и посмотрим, что происходит под капотом.

Я хочу уделить немного времени и обсудить код в строках 20–22 в версии AT&T, а также в версии Intel. Этот набор инструкций использует то, что мы называем программным прерыванием. В строке 20 синтаксиса AT&T mov $1,% eax означает, что мы перемещаем десятичное значение 1 в eax, который указывает вызов sys_exit, который правильно завершит выполнение программы обратно в Linux, чтобы не было ошибок сегментации. В строке 21 мы перемещаем $0, %ebx, который перемещает 0 в ebx, чтобы показать, что программа успешно выполнена, и, наконец, мы видим int $0x80.

Строки 20 и 21 устанавливают программное прерывание, которое мы вызываем в строке 22 с помощью инструкции int $0x80. Давайте углубимся в это дело.

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

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

33.jpg


Когда мы загружаем значения, как мы продемонстрировали выше, и вызываем INT 0x80, адрес следующей инструкции в пользовательском пространстве, раздел кода, который является вашим кодом, помещается в область обратного адреса в стеке. Это очень важно, так как когда INT 0x80 выполняет свою работу, он может правильно знать, какая инструкция должна быть выполнена следующей, чтобы гарантировать правильное и последовательное выполнение программы.

Имейте в виду, что в современных версиях Linux мы используем защищенный режим, что означает, что у вас НЕТ доступа к пространству ядра Linux. Все, что находится под длинной линией в середине диаграммы выше, представляет пространство ядра Linux.

Естественный вопрос: почему мы не можем получить к нему доступ? Ответ очень прост: Linux НЕ позволит вашему коду получить доступ к внутренним компонентам операционной системы, поскольку это было бы очень опасно, поскольку любое вредоносное ПО могло манипулировать этими компонентами ОС для отслеживания всех видов вещей, таких как нажатия клавиш, действия пользователя и тому подобное.

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

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

В самом низу области памяти, где существует сегмент 0, смещение 0, находится таблица поиска с 256 записями. Каждая запись представляет собой адрес памяти, включая сегменты и смещения, которые составляют 4 байта на запись, поскольку первые 1024 байта зарезервированы для этой таблицы, и НИКАКИМ ДРУГИМ КОДОМ нельзя манипулировать эти данные. Каждый адрес называется вектором прерывания, который включает целое, называемое таблицей векторов прерываний, где каждый вектор имеет номер от 0 до 255, начиная с которого вектор 0 занимает байты от 0 до 3. Это продолжается с вектором 1, который содержит от 4 до 7 и т. д.

Имейте в виду, что ни один из этих адресов не является частью постоянной памяти. Статическим является вектор 0x80, который указывает на диспетчер служб, который указывает на процедуры обслуживания ядра Linux.

Когда адрес возврата извлекается из стека, он возвращается к следующей инструкции, инструкция называется возвратом прерывания или IRET, которая завершает выполнение потока программы.

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

cat /usr/include/asm/unistd_32.h

Ниже приведен список лишь некоторых из них. Как вы можете видеть, 1 представляет sys_exit, который мы использовали в приведенном выше коде.

34.jpg


Начиная с этого урока, мы воспользуемся трехэтапным подходом:

1) Программа

2) Отладка

3) Хак

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

Мы не обязательно будем рассматривать вредоносные программы напрямую, так как я предпочитаю сосредоточиться на темах программ на языке ассемблера, которые дадут вам инструменты и понимание, чтобы ЛЮБУЮ программу можно было отлаживать и изменять по своему вкусу. Это цель этих руководств.

Информация, которую вы узнаете в этой серии руководств, также может использоваться с высокоуровневыми отладчиками графического интерфейса пользователя, такими как IDA Pro, однако я остановлюсь только на отладчике GNU GDB.

Я с нетерпением жду встречи с вами в следующем модуле, когда мы погрузимся в отладку созданной нашей первой программы!
 
Часть 23 - Отладка программы № 1 [Перемещение данных]

Начнем с загрузки двоичного файла в GDB.

Для загрузки в GDB введите:

gdb -q moving_immediate_dat

41.jpg


Давайте сначала установим точку останова при запуске, набрав b _start.

Затем мы можем запустить программу, набрав r.

Чтобы затем начать дизассемблирвоание, мы просто набираем disas.

Мы закодировали nop, что означает отсутствие операции или 0x90 с точки зрения опокоад для правильных целей отладки, которые правильно попали в точку останова. Это хорошая практика при создании ассемблерных программ.

42.jpg


Нативный синтаксис, как я уже много раз говорил ранее, - это синтаксис AT&T, который вы видите выше. Я намеренно мучительно хожу взад и вперед, чтобы вы чувствовали себя комфортно в каждом из них, однако в дальнейшем я буду придерживаться синтаксиса AT&T, однако хотел бы показать вам несколько примеров того и другого. Я еще раз заявляю, что если вы когда-нибудь захотите увидеть синтаксис Intel, просто введите set-disassembly-flavour intel, и у вас будет то, что вы ищете.

Сначала мы используем команду si, что означает переход к следующей инструкции. Здесь в _start+0 мы видим, что вы перемещаете шестнадцатеричное значение 0x64 в EAX. Это просто перемещение десятичной дроби 100 или, как ее видит компьютер, шестнадцатеричного 0x64 в EAX, что демонстрирует непосредственное перемещение значения в регистр.

43.jpg


Мы делаем степ-инто и затем используем команду i r, которая помнит, что между ними есть пробел, чтобы дать нам информацию о состоянии регистров процессора. Мы видим, что EAX теперь имеет значение 0x64 в шестнадцатеричном или 100 в десятичном формате.

44.jpg


После того, как мы снова сделаем степ-инто и сделаем disas, мы увидим, что мы переместили значение 0x50 в метку буфера, чтобы можно было вернуться к исходному коду.

Имея дело с нерегистровыми данными, мы можем использовать приведенную выше команду печати, когда мы набираем print /x buffer, и она ясно показывает нам, что значение внутри буфера равно 0x50. Обозначение /x означает отображение значения в шестнадцатеричном формате.

45.jpg


Следовательно, вы можете просмотреть слайд 2 этого руководства выше, вы видите в _start +5 непосредственное значение 0x50, загруженное в метку буфера, или в этом случае адрес буфера, который равен 0x8049090, и мы можем проверить его, используя инструкцию проверки, набрав x/xb 0x8049090, который показывает нам один шестнадцатеричный байт в этом месте, что дает 0x50.

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

Я с нетерпением жду встречи с вами на в следующем занятии, когда мы погрузимся в создание нашего первого ассемблерного хака!
 
Часть 24 - Хак ASM 1 [перемещение данных]

Начнем с загрузки двоичного файла в GDB.

Для загрузки в GDB введите:

gdb -q moving_immediate_data

51.jpg


Давайте сначала установим точку останова при запуске, набрав b _start.

Затем мы можем запустить программу, набрав r.

Чтобы затем начать дизассемблирование, мы просто набираем disas.

Мы закодировали nop, что означает отсутствие операции или 0x90 с точки зрения опкода для правильных целей отладки, которые правильно попали в точку останова. Это хорошая практика при создании программ.

52.jpg


Давай повеселимся! На этом этапе сделайте si один раз и сделайте i r, чтобы увидеть, что 0x64 действительно был перемещен в EAX.

53.jpg


Мы видим, что EAX имеет значение 0x64 или 100 в десятичной системе. Теперь давайте хакнем это значение, установив в EAX что-то вроде 0x66, набрав set $eax = 0x66.

54.jpg


БАМ! Ну вот! Вы можете увидеть НЕВЕРОЯТНУЮ мощность ассемблера здесь! Мы просто хакнули значение от 0x64 до 0x66 или от 100 до 102 в десятичной системе. Это тривиальный пример, однако вы можете ясно видеть, что когда вы научитесь осваивать эти концепции, вы приобретете большую власть над компьютером. С каждой программой, которую мы создаем, у нас будет очень простой урок, подобный этому, где мы захватим по крайней мере одну часть кода, чтобы мы могли не только видеть, как программа создается и отлаживается, но и как мы можем манипулировать ею так, как захотим.

Я с нетерпением жду встречи с вами в следующем модуле, когда мы погрузимся в создание нашей второй программы на асме!
 
Часть 25 - Программа № 2 [Перемещение данных между регистрами]

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

В частности, мы переместим значение из EDX в EAX. Мы инициализируем эту программу простым непосредственным значением 22, которое перейдет в EDX и, в конечном итоге, в EAX.

61.jpg


Имейте в виду, что вы можете перемещать только одинаковые регистры между собой. Мы знаем, что EAX и EDX - это 32-битные регистры. Мы знаем, что к каждому из этих регистров можно получить доступ по их 16-битным значениям как ax и dx соответственно. Вы не можете переместить 32-битное значение в 16-битное значение и наоборот.

Я с нетерпением жду встречи в следующем модуле, когда мы погрузимся в отладку нашей второй программы на асме!
 
Часть 26 - Отладка программы № 2 [Перемещение данных между регистрами]

Давайте отладим программу № 2:

1.jpg


Давайте запустим GDB и остановимся на _start, запустим двоичный файл и выполним disas:

2.jpg


Теперь давайте дважды выполним si и i r:

3.jpg


Как мы видим, 0x16 или десятичное значение 22 успешно перешло в EDX. А теперь давай еще раз выполним si.

4.jpg


Как видите, мы успешно переместили EDX в EAX.

Я с нетерпением жду встречи с вами в следующем модуле, когда мы погрузимся во взлом нашей второй программы!
 
Часть 27 - Взлом программы № 2 [Перемещение данных между регистрами]

Давайте взломаем вторую программу:

11.jpg


Давайте запустим GDB и остановимся на _start, запустим двоичный файл и выполним disas:

12.jpg


Теперь давайте дважды выполним si и i r:

13.jpg


Как мы видим, 0x16 или десятичное значение 22 успешно перешло в EDX. Это то, что мы сделали на прошлом уроке, но здесь мы собираемся использовать это значение для чего-нибудь еще.

Мы можем установить $edx = 0x19, например:

14.jpg


Как видите, мы легко изменили значение EDX до 0x19 или 25 десятичных знаков.

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

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

Я с нетерпением жду встречи с вами в следующем блоке, когда мы начнем писать нашу третью программу!
 
Часть 28 - Программа № 3 [Перемещение данных между памятью и регистрами]

В нашей третьей программе мы продемонстрируем, как мы можем перемещать данные между памятью и регистрами.

21.jpg


В частности, мы переместим константное значение в ECX.

Помните, что для ассемблирования мы набираем:

as –32 -o moving_data_between_memory_and_registers.o moving_data_between_memory_and_registers.s

Чтобы связать объектный файл, набираем:

ld -m elf_i386 -o moving_data_between_memory_and_registers moving_data_between_memory_and_registers.o

Я с нетерпением жду встречи с вами в следующем блоке, когда мы погрузимся в отладку нашей третьей программы!
 
Часть 29 - Отладка программы № 3 [Перемещение данных между памятью и регистрами]

Давай отлаживать!

31.jpg


В частности, мы переместим значение константы в ECX.

32.jpg


Мы открываем GDB в тихом режиме, прерываем работу на _start и запускаем, следуя приведенным выше командам.

33.jpg


Как мы видим, когда мы получаем информацию, и видим, чтозначение ECX равно 0.

34.jpg


После того, как мы сделаем два шага, мы видим, что значение ECX равно 10 или 0xa hex.
 
Часть 30 - Взлом программы № 3 [Перемещение данных между памятью и регистрами]

Теперь давайте взломаем!

41.jpg


В частности, мы переместим значение константы в ECX, как и раньше.

42.jpg


Мы открываем GDB в тихом режиме, прерываем работу на _start и запускаем, следуя приведенным выше командам.

43.jpg


Как мы видим, когда мы получаем информацию о регистрах, значение ECX равно 0. Давай сделаем si два раза

44.jpg


Как вы можете видеть, значение ECX - 10 или 0xa в hex, как это было в предыдущем уроке, теперь поменяем это значение на что-нибудь еще.

Установим $ecx = 1337 и выполним i r.

45.jpg


Как вы можете ясно видеть, мы поменяли значение ECX на 0x539 в шестнадцатеричном формате или 1337 в десятичном формате.

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

Я с нетерпением жду встречи с вами на следующем блоке, когда мы погрузимся в создание нашей четвертой программы!
 
Часть 31 - Программа № 4 [Перемещение данных между регистрами и памятью]

В нашей четвертой программе мы продемонстрируем, как мы можем перемещать данные между регистрами и памятью.

1.jpg


В частности, мы переместим непосредственное десятичное значение 777 в EAX. Затем мы перемещаем это значение, хранящееся в EAX, в ячейку памяти, которое изначально имело десятичное значение 10 во время выполнения. Имейте в виду, что мы могли бы назвать переменую как угодно, но я назвал его константой, так как оно было настроено как константа в разделе .data.

Вы можете ясно видеть, что им можно управлять, поэтому это НЕ константа. Я специально выбрал имя константа, как если бы она была в чистом виде, значение оставалось бы 10 в десятичной или шестнадцатеричным 0xa.

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

Помните, что для ассемблирования набираем:

as –32 -o moving_data_between_registers_and_memory.o moving_data_between_registers_and_memory.s

Чтобы слинковать объектный файл, набираем:

ld -m elf_i386 -o moving_data_between_registers_and_memory moving_data_between_registers_and_memory.o

Я с нетерпением жду встречи с вами в следующем модуле, когда мы погрузимся в отладку нашей четвертой программы.
 
Часть 32 - Отладка программы № 4 [Перемещение данных между регистрами и памятью]

В нашей четвертой программе мы продемонстрируем, как мы можем перемещать данные между регистрами и памятью.

21.jpg


В частности, мы переместим непосредственное десятичное значение 777 в EAX. Затем мы перемещаем это значение, хранящееся в EAX, в ячейкупамяти, которое изначально имело десятичное значение 10 во время выполнения. Имейте в виду, что мы могли бы назвать переменную как угодно, но я назвал её константой, так как она было настроена как константа в разделе .data.

22.jpg


Как вы можете видеть выше, мы переходим в GDB и ясно видим, что значение константы было заменено десятичным числом 777, где в коде оно было явно установлено в 10 в десятичной системе в строке 6 кода в начале этого руководства.

Мы ясно видим, что в строке 16 кода десятичное значение 777 было успешно перемещено в EAX и в значение константы в памяти.
 
Часть 33 - Взлом программы № 4 [Перемещение данных между регистрами и памятью]

Давайте еще раз рассмотрим исходный код.

31.jpg


Выше мы снова видим, что переместили непосредственное десятичное значение 777 в EAX. Затем мы перемещаем это значение, хранящееся в EAX, в ячейку памяти, которое изначально имело десятичное значение 10 во время выполнения. Имейте в виду, что мы могли бы назвать переменную как угодно, но я назвал его константой, так как оно было настроено как константа в разделе .data.

32.jpg


Как вы можете видеть выше, мы переходим в GDB и ясно видим, что значение переменной было заменено десятичным числом 777, где в коде оно было явно установлено в 10 в десятичной системе в строке 6 кода в начале этого руководства.

Мы ясно видим, что в строке 16 кода 777 в десятичной системе было успешно перемещено в EAX и в значение константы в памяти.

Теперь давайте взломаем эту программу!

33.jpg


Мы сделали те же шаги, что и в прошлый раз с уроком отладки. Здесь мы взломали значение константы, и поменяли значение 777 на 666.
 
Часть 3: Типы вредоносных программ

Чтобы просмотреть полное содержание всех уроков, нажмите ниже ссылку, так как в ней дается краткое описание каждого урока в дополнение к темам, которые он охватывает. https://github.com/mytechnotalent/Reverse-Engineering-Tutorial

Вредоносное ПО делится на несколько категорий, о которых я кратко коснусь ниже.

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

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

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

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

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

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

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

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

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

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

В следующем уроке мы начнем наше долгое путешествие в язык ассемблера x86. Чтобы по-настоящему понять самые основы реверс инжиниринга и вредоносных программ, нам нужно в течение следующих нескольких месяцев глубоко погрузиться в ядро и построить свой путь.
Thanks for sharing, I downloaded it was what I was looking for
 
Часть 34 - Программа ASM 5 [Косвенная адресация с помощью регистров]

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

1520086819422.jpg


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

Это создает последовательный ряд значений, помещаемых в память. Каждое значение данных занимает одну единицу памяти, которая является целым числом.

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

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

Имейте в виду, что массив начинается с индекса 0. Поэтому в приведенном выше коде мы видим, что 1 переходит в edi, который является вторым индексом, который в конечном итоге переходит в ebx.

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

Помните, что для сборки набираем:

as –32 -o Indirect_addressing_with_registers.o косвенный_addressing_with_registers.s

Чтобы слинковать объектный файл, набираем:

ld -m elf_i386 -o Indirect_addressing_with_registers Indirect_addressing_with_registers.o

Я с нетерпением жду встречи с вами в следующей главе, когда мы погрузимся в отладку нашей пятой программы!
 
Часть 35 - Отладка программы № 5 [Косвенная адресация с помощью регистров]

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

1.jpg


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

Я сознательно выбрал этот путь, чтобы вам было удобно работать с самой сложной версией x86. Если вы запутались с этим синтаксисом, просмотрите предыдущие уроки, поскольку я рассматривал различия между ними.

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

objdump -d -M intel Indirect_addressing_with_registers | grep _start .: -A24

2.jpg


А теперь вернемся к нашей программе.

Давайте загрузим двоичный файл в GDB и остановимся на метке _start, сделаем несколько шагов и проверим 6 из 11 значений внутри метки константы.

3.jpg


Затем мы перемещаем адрес памяти метки в edi и перемещаем непосредственное десятичное значение 25 во второй индекс нашего массива. По сути, это взлом исходного кода, поскольку мы меняем исходное значение с 8 на 25.

Если вы посмотрите исходный код, вы увидите строку 18, в которой мы загружаем значение 1 в edi. Имейте в виду, что это второе значение, поскольку массивы начинаются с 0.

4.jpg


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

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

Я с нетерпением жду встречи с вами в следующем модуле, когда мы погрузимся во взлом нашей пятой ассемблерной программы!
 
Часть 36 - Взлом программы № 5 [косвенная адресация с помощью регистров]

Давайте еще раз исследуем исходник.

21.jpg


Давайте еще раз загрузим двоичный файл в GDB и остановимся на метке _start.

22.jpg


Как мы видим выше, мы видим команду print * 0x804909e. Мы видим, что это дает значение 5. Двоичный код во время выполнения помещает значения внутри метки константы по соответствующему адресу памяти.

В этом случае мы видим, что указатель на 0x804909e или *0x804909e содержит 5, как мы заявили выше. Целое число содержит 4 байта данных. Следующее значение в нашем массиве будет сохранено в адрес 0x80490a2. Эта ячейка памяти будет содержать значение 8.

Если бы мы продолжали перемещаться по массиву, мы бы переместили 4 байта к следующему значению и так далее. Помните, что каждая ячейка памяти в 32-битном коде x86 содержит 4 байта данных.

Давай взломаем это!

23.jpg


После того, как мы прервались на _start и запустили, мы исследовали массив, как и в предыдущем уроке. Здесь мы хакаем значение по адресу 0x80490a2 до 66 вместо десятичного числа 8 и видим, что мы успешно изменили один элемент массива.

Этот урок очень важен для понимания того, как массивы в конечном итоге хранятся в памяти и как ими манипулировать и взламывать. Если у вас есть вопросы, оставьте их в комментариях ниже.

Я с нетерпением жду встречи с вами в следующем уроке, когда мы погрузимся в программирование нашей шестой программы на ассемблере!
 
Часть 37 - Программа ASM 6 [инструкции CMOV]

В нашей шестой программе мы продемонстрируем, как мы можем работать с инструкциями CMOV.

Прежде чем мы углубимся в код, давайте поговорим о CMOV.

Есть беззнаковые инструкции CMOV, такие как:

CMOVA or CMOVNBE = Above [Carry Flag or Zero Flag = 0]

CMOVAE or CMOVNB = Above Or Equal [Carry Flag = 0]

CMOVNC = Not Carry [Carry Flag = 0]

CMOVB or CMOVNAE = Below [Carry Flag = 1]

CMOVC = Carry [Carry Flag = 1]

CMOVBE or CMOVNA = Below Or Equal [Carry Flag or Zero Flag = 1]

CMOVE or CMOVZ = Equal [Zero Flag = 1]

CMOVNE or CMOVNZ = Not Equal [Zero Flag = 0]

CMOVP or CMOVPE = Parity [Parity Flag = 1]

CMOVNP or CMOVPO = Not Parity [Parity Flag =0]

Также имеются знаковые инструкции CMOV, такие как:

CMOVGE or CMOVNL = Greater Or Equal [Sign Flag xor Overflow Flag = 0]

CMOVL or CMOVNGE = Less [Sign Flag xor Overflow Flag = 1]

CMOVLE or CMOVNG = Less Or Equal [Sign Flag xor Overflow Flag or ZF = 1]

CMOVO = Overflow [Overflow Flag = 1]

CMOVNO = Not Overflow [Overflow Flag = 0]

CMOVS = Sign NEGATIVE [Sign Flag = 1]

CMOVNS = Not Sign POSITIVE [Sign Flag = 0]

Не забывайте проверять какой является операция, знаоквая или беззнаковая. Беззнаковые инструкции используют CF, ZF и PF для определения разницы между двумя операндами, в то время как знаковые инструкции используют SF и OF для указания условия сравнения операндов.

Если вам нужно освежить в памяти флаги, просмотрите Часть 14, посвященную флагам, в этой серии.

Команды CMOV полагаются на математическую команду, которая устанавливает регистр EFLAGS для работы и, следовательно, позволяет программисту использовать операторы JMP после оператора сравнения. Давайте исследуем исходный код.

31.jpg


Хорошо, давайте начнем со строк 21 и 22. В этом нет ничего нового, поскольку мы просто перемещаем массив в ebx.

В строке 24 мы видим функцию find_smallest_value, в которой мы циклически перебираем массив и используем CMOVB, чтобы в конечном итоге найти наименьшее значение.

Мы видим cmp% ebx,% eax, из которого cmp вычитает первый операнд из второго ,и соответствующим образом устанавливает регистр EFLAGS. На этом этапе cmovb используется для замены значения в ebx на значение в eax, если значение меньше того, что было изначально в регистре ebx.

После выхода из цикла мы видим три набора sys_writes для первого отображения нашего сообщения, второй для отображения преобразованного целого числа в значение ascii.

Помните, что для ассемблирования набираем:

as –32 -o cmov_instructions.o cmov_instructions.s

Чтобы слинковать объектный файл, набираем:

ld -m elf_i386 -o cmov_instructions cmov_instructions.o
 
Часть 38 - Отладка программы № 6 [инструкции CMOV]

Давайте еще раз рассмотрим исходный код.

41.jpg


Давайте остановимся на адресе 0x08048092, который является строкой 31. Давайте сделаем r для запуска и наберем print $ ebx. Мы видим значение 7.

42.jpg


Хорошо, теперь давайте остановимся на адресе 0x080480b1, который является строкой 46. Помните, что когда мы изучаем значение, оно было преобразовано в его печатаемый эквивалент в формате ascii, поэтому, чтобы увидеть значение 7, вы должны ввести x /1c &answer.

43.jpg
 
Часть 39 - Взлом программы № 6 [инструкции CMOV]

Давайте перенесем двоичный файл в gdb.

51.jpg


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

52.jpg


Мы устанавливаем $eip равным 0x080480dd, что является процедурой выхода. Теперь мы видим, что отладчик обходит весь код из инструкции nop. Теперь вы можете использовать эту команду для перехода в любое место внутри любого двоичного файла в отладчике.

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


Напишите ответ...
  • Вставить:
Прикрепить файлы
Верх