Привет . В этой статье я собираюсь показать вам основы ассемблера. Перед этим давайте кое-что проясним. В этом уроке я собираюсь научить вас 64-битной сборке. Сборка имеет два синтаксиса — Intel,ATT. В этом уроке я буду использовать синтаксис Intel. Ассемблер, который я буду использовать, называется NASM или Netwide Assembler.

Почему вы должны изучать ассемблер?

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

Некоторые важные термины

Стдин

stdin – это входной поток, в который данные отправляются и считываются программой.

Стандартный

Stdout — это сокращенная форма стандартного вывода. Это выходной поток, в котором процесс или программа может записывать данные для отображения на экране.

Системный вызов

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

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

section .data
        text db "Hello World!",10
section .text
        global _start
_start:
        mov rax, 1
        mov rdi, 1
        mov rsi, text
        mov rdx, 12
        syscall
mov rax, 60
        mov rdi, 0
        syscall

В программе сборки есть три раздела

.данные

Этот раздел содержит инициализированные переменные.

section .data
        text dt "Hello World!",10

Здесь текст — это имя переменной. dt означает определение 10 байтов. 10 используется для разрыва строки

section .text
        global _start
_start:
        mov rax, 1
        mov rdi, 1
        mov rsi, text
        mov rdx, 12
        syscall
        mov rax, 60
        syscall

.text используется для хранения инструкций. Глобальный _start сообщает ядру, где начинается выполнение. Есть еще один раздел под названием .bss . Я не использовал его. Используется для хранения неинициализированных переменных.

Теперь давайте разберемся с программой.

        mov rax, 1
        mov rdi, 1
        mov rsi, text
        mov rdx, 12
        syscall

Каждый системный вызов имеет уникальный идентификатор. Идентификатор системного вызова попадает в регистр rax. Мы выполняем операцию mov, которая перемещает 1 в rax.

mov rdi, 1

В этой строке мы перемещаем 1 в rdi. Регистр rdi содержит файловый дескриптор. Он может содержать три значения. stdin со значением 0, stdout со значением 1 и stderr со значением 2. Поскольку мы хотим печатать, мы будем использовать stdout(1)

        mov rsi, text
        mov rdx, 12
        syscall

В этой строке мы помещаем адреса переменной text в rsi, а в следующей строке мы помещаем общее количество символов в rdi. В моем случае это 12. Хитрость заключается в том, чтобы поставить правильное значение в нужное место и сделать системный вызов.

mov rax, 60
syscall

В приведенной выше строке мы делаем вызов ядра sys_exit. Идентификатор sys_exit равен 60. Итак, мы переместили 60 в rax.

Теперь соберем программу

nasm -f elf64 -o hello.o helloworld.asm
ld hello.o -o hello

Теперь сделайте программу исполняемой и запустите ее.

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

В этой программе я помещаю неправильные значения в неправильный регистр. Вот результат