понедельник, 23 октября 2017 г.

Примеры на Ассемблер



АССЕМБЛЕР
РЕГИСТР - ячейка памяти для того чтобы выполнять действия, например сложить два числа. 
АССЕМБЛЕРНАЯ ПРОГРАММА наполовину состоит из команд пересылки данных.
АДРЕСНОЕ ПРОСТРАНСТВО — это просто совокупность ячеек виртуальной памяти, доступной процессору. 
ОБЛАСТЬ КОДА
ОБЛАТЬ ДАННЫХ 
СТЕК
ПОДРОГРАММА-ПРОЦЕДУРА
В простейшем случае (в ассемблерах) подпрограмма представляет собой последовательность команд (операторов), отдельную от основной части программы и имеющую в конце специальную команду выхода из подпрограммы.
СТЕК — это способ хранения данных, представляющий собой нечто среднее между списком
и массивом.

РЕГИСТРЫ EAX, EBX, ECX, EDX, ESI, EDI, EBP (32-разрядные регистры)называются регистрами общего назначения и могут свободно участвовать в любых математических операциях или операциях обращения к памяти.

.text - (СЕКЦИЯ КОДА) эта секция содержит исполняемый код. Благодаря 32-битной плоской адресации содержимое аналогичных секций всех объектных файлов, подаваемых на вход линкера, собирается в одной секции .text исполняемого PE-файла.
  
.data - (СЕГМЕНТ ДАННЫХ)содержит инициализированные и глобальные переменные. 
.idata - содержит данные об импортируемых приложением функциях, то бишь таблица импорта. 
Эта таблица состоит из 
1) массива с описанием используемых DLL'ок, 
2) двух массивов с адресами импортируемых функций и   
3) массива имен импортируемых функций. 
.rdata - содержит данные, доступные только для чтения, как-то: литеральные строки, константы, отладочную информацию.

MOV - Команда пересылки данных или оператор присваивания. 

MOV EAX, 333H -> ОПЕРАТОР ПРИСВАИВАНИЯ 
MOV EAX, EBX -> то же что 333h -> оператор присваивания 
MOV EAX, [EBX] => УКАЗАТЕЛИ 
MOV EAX, [EBX + 66H] => УКАЗАТЕЛЬ СО СМЕЩЕНИЕМ 

ОБЪЯВЛЕНИЕ ПЕРЕМЕННЫХ И ТИПЫ ДАННЫХ 
db - переменная с типом данным один байт -> 8 бит
dw - переменная с типом данных слово - > зависит от типа ОС 
dd - переменная с типом данным двойное слово -> зависит от типа ОС 

ЗАГРУЗКА ПЕРЕМЕННОЙ 
LEA -> Команда 
MOV OFFSET

Листинг 1. ОСНОВНЫЕ МЕТОДЫ ПЕРЕСЫЛКИ ДАННЫХ 
LEA EDX,b                    ;Регистр EDX содержит указатель на переменную b
MOV EBX,a                   ;Регистр EBX содержит значение переменной a
MOV ECX, offset a        ;Регистр ECX содержит указатель на переменную a
MOV [EDX],EBX         ;Скопировать переменную a в переменную b
MOV b, EBX                 ;Скопировать переменную a в переменную b
a DD 66h                        ;Объявляем переменную a типа двойного слова и
                                        ;Инициализируем ее числом 66h
b DD ?                            ;Объявляем неинициализированную переменную b типа двойного слова

ОСНОВНЫЕ ТИПЫ УСЛОВНЫХ ПЕРЕХОДОВ 
CMP EAX, EBX                           ;Сравнить EAX и EBX
JZ xxx                                            ;Если они равны, сделать переход на xxx
CMP [ECX], EDX                         ;Сравнить *ECX и EDX
JAE yyy                                         ;Если беззнаковый *ECX >= EDX, то перейти на yyy

КОМАНДЫ БЕЗУСЛОВНОГО ПЕРЕХОДА 
JB (JUMP IF BELOW) ПЕРЕХОД ЕСЛИ ПРИЕМНИК МЕНЬШЕ ИСТОЧНИКА
JBE (JUMP IF BELOW OR EQUAL) ПЕРЕХОД ЕСЛИ МЕНЬШЕ ИЛИ РАВНО
JNB (JUMP IF NOT BELOW) ПЕРЕХОД ЕСЛИ НЕ МЕНЬШЕ (РАВНОСИЛЬНА JAE)
JA (JUMP IF ABOVE)    ПЕРЕХОД ЕСЛИ БОЛЬШЕ
JAE (JUMP IF ABOVE OF EQUAL)    ПЕРЕХОД ЕСЛИ БОЛЬШЕ ИЛИ РАВНО
JNA (JUMP IF NOT ABOVE)  ПЕРЕХОД ЕСЛИ НЕ БОЛЬШЕ (РАВНОСИЛЬНА JBE)

 ВЫЗОВ ФУНКЦИЙ НА АССЕМБЛЕРЕ 
 Два типа соглашений о вызовах (calling conventions) - C и Pascal 

 ФУНКЦИИ API ОПЕРАЦИОННОЙ СИСТЕМЫ WINDOWS (ВНЕШНИЕ ФУНКЦИИ)
 stdcall -> API, библиотеки

Листинг 2.  ВЫЗОВ ФУНКЦИЙ  API ОС
PUSH offset LibName                                       ;Засылаем в стек смещение строки
CALL LoadLibrary                                            ;Вызов функции
MOV h, EAX                                                     ;EAX содержит возращенное значение

Современные средства обратной разработки автоматически распознают библиотечные функции, локальные переменные, аргументы стека, типы данных, ветвления, циклы и т. д. По всей вероятности, вскоре дизассемблеры смогут и генерировать код, по виду подобный коду, написанному на языках высокого уровня.
  
; --------------- S U B R O U T I N E -------------------------------------------------------------------
; Моя первая программа с комментариями 
CEGM Segment ;название программы - CEGM (кода, процедуры)
org 100h ;отсчет начала смещения 100h (16-ная система h-hex) 
Begin:
mov ah,9 ;move - загрузить в регистр ah число 9
mov dx,offset Message ;move - загружаем в регистр dx адрес сообщения Message (offset - смещение)
int 21h ;int - interrupt прерывание
int 20h ;int - interrupt прерывание выход из программы DOS аналогично exit
Message db 'Hello all$'          ;вывод на экран сообщения $-конец выводимой строки
CEGM ends  ;конец программы CEGM
end Begin                            ;конец тела кода Begin

; --------------- S U B R O U T I N E --------------------------------------------------------------------

;Моя вторая программа
CSEG Segment ;название программы, алгоритма
org 100h ;отсчет начала смещения 100h (16-ная система h-hex) 
_beg:
mov ax, 0B800h ;загражаем в регистр ax число 0B800h 
mov es, ax ;загружаем в сегментный регистр es число 0B800h 
mov di, 0 ;в регистре di ноль смещения относительно сегмента 0B800h 
mov ah, 31 ;загружаем в регистр ah рожицу 31
mov al, 1 ;в регистре al рожица
mov es:[di], ax ;[] указывает, что число загружается не в адрес 0B800h:0000h, а по адресу
mov ah, 10h ;move - загрузить в регистр ah число 10h (hex)
int 16h ;прервывание
int 20h ;прервывание - вывод рожицы на экран
CSEG ends ;конец алгоритма
end _beg ;конец кода 

; --------------- S U B R O U T I N E ------------------------------------------------------------------

;Изучаем циклы loop, cx
;оператор loop
; ЭТО тело цикла 
; cx - условный переход - есть условия цикла (сетчик)
mov cx, 3 ;загружаем в cx(цикл) три повтора -> сx - цикл, 3 - кол-во повторов (счетчик)
Label_1         ;метка (название)
mov ah, 9      ;move - загрузить в регистр ah число 9
mov dx, offset Str      ;move - загружаем в регистр dx адрес сообщения Message (offset - смещение)
int 21h ;прерывание
loop Lavel_1 ;уменьшает на 1 содержимое регистра сx и возвращается если не ноль. 

; --------------- S U B R O U T I N E ---------------------------------------
;jump Безусловный переход - передача управления по другому адресу, на указанную метку не зависимо от условия 

mov ah,9     ;move - загрузить в регистр ah число 9
mov dx, offset Str ;move - загружаем в регистр dx адрес сообщения Message (offset - смещение)
int 21h ;прерывание 
jmp Label_2 ;(50-51) выполняться не будут. Будет выведено сообщение на экран и переход на (52) label_2 (метка)
add cx, 2
dec cx
Label_2 ;метка
int 20h ;прерывание

; --------------- S U B R O U T I N E ------------------------------------------------------------------

;Оптимизация 
CSEG Segment ;название программы, алгоритма
org 100h ;отсчет начала смещения 100h (16-ная система h-hex) 
_beg:
mov ax, 0B800h ;загражаем в регистр ax число 0B800h 
mov es, ax ;загружаем в сегментный регистр es число 0B800h 
mov di, 0 ;в регистре di ноль смещения относительно сегмента 0B800h 
mov al, 1 ;в регистре al рожица
mov ah, 31
mov cx, 2000 ;цикл с количеством повторов 2000
Next_face: ;метка "голова цикла"
mov es:[di], ax ;записываем в видеобуфер по адресу 0B800:di число, находящееся в ax (атрибут+символ)
add di, 2 ;увеличиваем значение данных в регстре di на 2
loop Next_face ;счетчик
mov ah, 10h ;move - загрузить в регистр ah число 10h (hex)
int 16h ;прервывание
int 20h ;прервывание - вывод рожицы на экран
CSEG ends ;конец алгоритма
end _beg ;конец кода 

; --------------- S U B R O U T I N E ----------------------------------------------------------------------------
; Вызов подпрограммы call 

mov dx, offset Mess1 ;загружаем в dx адрес строки Mess1
call out_string ;вызывает подрограмму c названием out_string 
call wait_key ;вызывает подрограмму c названием wait_key
mov dx, offset Str ;move - загружаем в регистр dx адрес сообщения Message (offset - смещение)
call out_string ;вызывает подрограмму c названием out_string 
call wait_key ;вызывает подрограмму c названием wait_key
int 20h ;прервывание 
out_string proc 
mov ah,9 ;move - загрузить в регистр ah число 9
int 21h ;прерывание
ret ;компьютер восстанавливает сохраненный адрес return и переходит на метку
out_string endp ;конец процедуры 
wait_key proc
mov ah,10h
int 16h ;прерывание
ret ;возврат 
wait_key endp
Press1 db "Put any key$"
Press2 db "You are success$"

; --------------- S U B R O U T I N E ----------------------------------------------------------------------------
;Listing example
CEGM Segment     ;название программы - CEGM (кода, процедуры)
assume cs:CEGM, ds:CEGM, es:CEGM, ss:CEGM  ;сегментные регистры привязаны к единственному сегменту CEGM
org 100h  ;отсчет начала смещения 100h (16-ная система h-hex) 
Start:
mov ax, 0B800h  ;загражаем в регистр ax число 0B800h 
mov es, ax ;загружаем в сегментный регистр es число 0B800h 
mov al, 1 ;в регистре al рожица
mov cx, 254 ;цикл с количеством повторов 254
Next_screen: ;голова цикла
mov di, 0 ;данные в регистре di будут меняться поэтому di->обнуление
call out_chars ;вызываем процедуру, выводящую на экран код, который находится в al
inc al
loop Next_screen ;цикл - счетчик 
mov ah,10 ;move - загрузить в регистр ah число 10
int 16h ;прерывание 
int 20h  ;прерывание
Out_chars proc ;процедура с названием out_chars
mov dx,cx ;сохранение содержания регистра cx (просто переносим его в dx) Далее идет вложенный цикл
mov cx, 2000 ;цикл с количеством повторов 2000
Next_face:
mov es:[di], ax ;записываем в видеобуфер по адресу 0B800:di число, находящееся в ax (атрибут+символ)
add di, 2 ;увеличиваем значение данных в регстре di на 2
loop Next_face ;(119) (122) голова и хвост цикла
mov dx,cx ;сохранение содержания регистра cx (просто переносим его в dx) Далее идет вложенный цикл
ret ;return возврат
Out_chars endp ;конец процедуры Out_chars
CEGM ends ;конец программы CEGM
end Start

; --------------- S U B R O U T I N E ----------------------------------------------------------------------------
;Работа со стеком 
push   ebx ;сохранить в стеке данные регистра ebx (регистр общего назначения ebx-32 бит, регистр базы)
mov    bl, [esp+arg_0] ;загрузить данные в bl, esp
push   esi ;сохранить данных в esi
mov    esi, ecx ;загрузим данные в esi, ecx 
pop    esi ;достанем данные их esi
pop    ebx ;достанем дынне из ebx 

; --------------- S U B R O U T I N E ----------------------------------------------------------------------------
CEGM Segment ;название программы - CEGM (кода, процедуры)
assume cs:CEGM, ds:CEGM, es:CEGM, ss:CEGM ;сегментные регистры привязаны к единственному сегменту CEGM
org 100h ;отсчет начала смещения 100h (16-ная система h-hex) 
Start:
Begin: 
mov ax,3D00h ;загрузить данные в ax
mov dx,offset File_name
int 21h ;прерывание
jc Error_file    ;jump if carry - переход, если флаг переноса не установлен

mov Handle,ax
mov bx,ax
mov cx,0FDE8h
mov dx,offset Buffer
int 21h

mov ah,3Eh
mov bx,Handle
int 21h

mov dx,offset Mess_ok
Out_prog:
mov ah,9
int 21h ;прерывание 

int 20h ;прерывание 

Error_file:
mov dx,offset Mess_error
jmp Our_prog          ;jump 

;-------Переменные-------
Handle dx,0
Mess_ok db 'Файл загружен в память! Смотрите в отладике!$'
Mess_error db 'Не удалось открыть файл'

;Будем читать этот файл:
File_name db 'c:\msdox.sys',0,'!$'

Buffer equ $
CSEG ends
end Begin

jnc ;jump if not carry  (переход если флаг не установен)
; --------------- S U B R O U T I N E ----------------------------------------------------------------------------
;Review

call Wait_key         ;ждем нажатия клавиши
cmp al,27 ;это <Esc>?

;если да - то на мету Quit_prog (quit - выход, prog (programm) - программа)
je Quit_prog ;jump if equil
cmp al,0 ;код клашиви расширенный?
je Begin ;да - повторим запрос 

;вызываем процедуру вывода нажатой клавиши на экран 
call Out_char
jmp Begin ;ждем дальше

;метка, на которую придет программа в случае нажатия клавиши <Esc>
Quit_prog:
mov al,32 ;помещаем в al <пробел>

Вызываем процедуру выода символ в al (в данном случае - пробела). Здесь мы как бы "обманываем" процедуру Out_char, которая нужна для выода нажатого символа на экран. Мы симулируем нажатие ;клавиши <пробел> и вызываем процедуру. 

call Out_char
int 20h ;выходим в DOS

;------Out_char-----         ;процедура (комменатрий)
Out_char proc ;начало процедуры

;сохраним все регистры, которые будут изменены подпрограммой...
push cx
push ax
push es ;сохраним сегментный регистр

push ax ;сохраним ax, т.к. в нем код нажатой 

mov ax,0B800h ;установим es на сегмент видеобуфера
mov es,ax

mov di,0                       ;di - первый символ первой строки

;выводим 2000 символов (80 символов в строке * 25 строк)

mov cx,2000
pop ax ;восстановим код клавищи 
mov ah,31

Метка для цикла в который выполниться 2000 раз.

Next_sym:
; заносим код клавиши и ее цвет (цвет всегда 31)

mov es:[di],ax

;увеличиваем указатель на 2 (первый байт - символ, второй байт - цвет)

inc di
inc di
loop Next_sym ;обработка следующего символа

;восстановим сохраненные регистры и выровняем стек 
pop es
pop ax
pop cx
ret ;вернемся из подпрограммы

Out_char endp


; --------------- S U B R O U T I N E ----------------------------------------------------------------------------
;РАБОТА С ФАЙЛАМИ

Begin: 
mov ax,3D00h                      ;будем открывать файл для чтения
mov dx,offset File_name        ;ds:dx указывают на путь к файлу
int 21h                                 ;открываем 
jc Error_file                          ;jump if carry - переход если установлен флаг переноса

Если произошла ошика (нет такого файла, слишком много открытых файлов, ошибка чтения) - то переходим на метку Error_file.

Запомним номер файла в переменной Handle.

Для того, чтобы прочитать файл, нужно в bx указать его номер, ;полученный после открытия, который находится в ax. Загрузка числа в один регистр из другоо (а, тем более, если используется ax) происходит выстрее, чем из памяти (переменной). Поэтому загружаем из ax, а не из переменной. Хотя запись mov bx, Handle не будет ошибочной. 

mov Handle, ax ;запомним номер файла в переменной Handle
mov bx,ax
mov ah,3Fh ;функция 3Fh - чтение файла
mov cx,0FDE8h ;будем читать 0FDE8h = 65000 байт 

;ds:dx  должен указать на буфер в памяти для чтения 

mov dx,offset Buffer 
int 21h ;все готово. Читаем

mov ah,3Eh ;закрываем файл 

Номер файл должен находиться в bx. Но т.к. регистр bx менялся, то загрузим его с нашей переменной (Handle).

mov bx,Handle
int 21h ;закрываем файл

Загрузим в dx строку с сообщением о том, что все в порядке. 

mov dx,offset Mess_ok ;занесет в dx последний свободный байт в нашем сегменте 

Out_prog: mov ah,9 ;функция 09h - вывод строки на экран
int 21h ;выводим троку
int 20h ;вывходим из программы

;Загрузим в dx строку с сообщением о том, то не смогли 
;открыть файл

;пойдем на Out-prog (зачем на дублировать код, если он уже есть?)
jmp Out_prog ;jump переход к программе

;-------------------------Данные------------------------
Handle dw 0 ;резерв 2 байта для нашей переменнй 
Mess_ok db 'Файл загружен! Смотрите в отладчике!$'
Mess_error db 'Не удалось открыть (найти) файл'
File_name db 'c:\msdos.sys',0,'!$'
Buffer equ $

; --------------- S U B R O U T I N E ----------------------------------------------------------------------------

;ОТКРЫТИЕ, ЧТЕНИЕ И ВЫВОД ФАЙЛА НА ЭКРАН 
CEGM Segment ;название программы - CEGM (кода, процедуры)
assume cs:CEGM, ds:CEGM, es:CEGM, ss:CEGM ;сегментные регистры привязаны к единственному сегменту CEGM
org 100h ;отсчет начала смещения 100h (16-ная система h-hex) 
;---------Начало--------------------------------------------
Begin:
mov dx,offset File_name      ;ds:dx указывают на путь к файлу
call Open_file                      ;вызвать подпрограмму Open_file
jc Error_file                        ;jump if carry - переход если установлен флаг переноса 
;---------Открыли файл--------------------------------------

mov bx,ax
mov ah,3Fh
mov cx,offset Finish-100h
mov dx,offset Begin

;-----------Прочитай файл-----------------------------------

call Close_file

;--------Вывод сооюещния----------------------------------
mov ah,9
mov dx,offset Mess_ok
int 21h
ret

;---------------Не смогли найти файл----------------------
Error_file:
mov ah,2
mov dl,7
int 21h
ret

;Процедуры
; ---------Открытие файла----------------------------------
Open_file proc 
cmp Handle,0FFFFh
jne Quite_open 
mov ax,3D00h
int 21h
mov Handle,ax
ret
Quit_open:
stc
ret
Handle dw 0FFFFh
Open_file endp

;--------Закрытие файла------------------------------
Close_file proc
mov ah,3Eh
mov bx,Handle
int 21h
ret
Close_file endp

;Данные
File_name db 'Porg09.com',0
Mess_ok db 'Все нормально!', 0Ah, 0Dh, '$'

Finish equ $

CSEG ends
end Begin 

; --------------- S U B R O U T I N E ----------------------------------------------------------------------------
; ФАЙЛОВАЯ ОБОЛОЧКА, ВИРУС, РЕЗИДЕНТ 
; ВВЕДЕНИЕ В ВИРУСОЛОГИЮ. ОБРАБОТЧИК ПРЕРЫВАНИЙ 


;ОТКРЫТИЕ, ЧТЕНИЕ И ВЫВОД ФАЙЛА НА ЭКРАН 
CEGM Segment ;название программы - CEGM (кода, процедуры)
assume cs:CEGM, ds:CEGM, es:CEGM, ss:CEGM ;сегментные регистры привязаны к единственному сегменту CEGM
org 100h ;отсчет начала смещения 100h (16-ная система h-hex) 

Begin:
;Открываем файл с помощью спецпроцедуры
mov dx,offset File_name ;ds:dx указывают на путь к файлу
call Open_file ;Открываем файл с именем Prog09.com
jc Error_file ;Переходим на метку Error_file при неудаче
mov bx,ax ;Сохраняем идентификатор файла

;Чтение файла
mov ah, 3Fh

;Загружаем длину нашей программы (кол-во читаемых байт) в регистр cx
mov cx,offset Finish-100h
mov dx,offset Begin ;И читаем файл в память, начиная с метки Begin.
int 21h

call Close_file ;Закрываем файл с помощью спецпроцедуры

;Выводим сообщение об удачном завершении
mov ah,9
mov dx,offset Mess_ok
int 21h
ret ;заверешение программы

;Если файл с указанным именем не нашли (File_name db 'Prog09.com', 0), 
;то выдаем звуковой сигнал и выходим

Error_file:
mov ah,2
mov dl,7
int 21h
ret

;Процедуры
;Процедура открытия файла для чтения 
Open_file proc
cmp Handle, 0FFFFh ;Выясним, открыт ли файл
jne Quite_open ;И если не открыт - открываем его. 
mov ax,3D00h
int 21h
mov Handle,ax
ret
Quite_open:
stc ;Устанавливаем флаг переноса в 1б необходимый
ret ;для подтверждения факта открытия файла (для jc (jump if carry))

Handle dw 0FFFFh         ;dw - 2 byte
Open_file endp ;end procedure

;Процедура закрытия файла
close_file proc
mov ah,3Eh
mov bx,Handle
int 21h
ret
Close_file endp

File_name db 'prog09.com',0

;0Ah, 0Dh - переход в начало следующей строки 
Mess_ok db 'Все нормально!',0Ah,0Dh,'$'

Finish equ $ ;Признак (адрес) конца кода программы.

CEGS ends
end Begin 

; --------------- S U B R O U T I N E ----------------------------------------------------------------------------

;ВИРУС
;МЫ БУДЕМ РАССМАТРИВАТЬ НЕРЕЗЕДЕНТНЫЙ ВИРУС, ЗАРАЖАЮЩИЙ COM-ФАЙЛ
;(САМЫЙ ПРОСТОЙ)

;ЧТО БУДЕТ ДЕЛАТЬ ВИРУС?
;НИЧЕГО, КРОМЕ РАЗМНОЖЕНИЯ 

Резидентная программа (резидент) - программа, которая постоянно ;находится в памяти. Пример резидента является драйвер мыши. Прерывание - это своего рода процедура (подпрограмма), которая ;имеет не название (напрмер print_string), а номер. Всего существует 256 прерываний. Некоторые номера зарезервированы например 16h.

Программные прерывания вызывает непосредственно программа при помощи команды int (отсюда и название - программные).

;Пример
mov ah,0
int 16h

;Пример
mov ah,9
int 21h

Аппаратные прерывания вызываются самостоятельно процессором (аппаратурой компьютера) при возникновении каких-л событий. 
регистры ss, sp

ОБРАБОТЧИК ПРЕРЫВАНИЙ
CEGM Segment ;название программы - CEGM (кода, процедуры)
assume cs:CEGM, ds:CEGM, es:CEGM, ss:CEGM ;сегментные регистры привязаны к единственному сегменту CEGM
org 100h ;отсчет начала смещения 100h (16-ная система h-hex) 
Start:
;Переходим на метку инициализации. Нам нужно будет перехватить прерывание
;21h, а также оставить программу резидентской в памяти

jmp Init

Ниже идет сам код обработчика прерывания 21h (он будет резидентный). После того как программа выйдет, процедура Init_21h_proc останется в памяти и будет контролировать функцию 09 прерывания 21h. Далее идет код обработчика.

Init_21h_proc proc
cmp ah,9 ;Проверим: это функция 09h
je ok_09 ;je - jump if equil 

;Если нет, перейдем на оригинальный обработчик прерывания 21h.
;Все. На метку ok_09 программа уже не вернется

jmp dword ptr cs:[Int_21h_vect]

Ok_09:
push ds ;Сохраним регистры 
push dx
push cs ;Адрес строки должен быть в ds:dx
pop ds

Выводим нашу строку [My_string] вместо той, которую должна была вывести программа, вызывающая 21h-e прерывание.

mov dx,offset My_string
pushf ;Эта инструция здесь необходима
call dword ptr cs:[Int_21h_vect]

pop dx ;Восстановим использование регистры
pop ds
iret         ;Продолжим работу (выйдем из прерывания)

Программа, выводящая строку, считает, что на экран было выведено ее сообщение. Но на самом деле это не так!

Переменная для хранения оригинального адреса обработка 21h
Int_21h_vect dd?

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

Init:

Установим наш обработчик (Int_21h_pro) (адрес нашего обработчика) на прерывание 21h. Это позволяет сделать функция 25h прерывание 21h. Но прежде нам нужно запомнить оригинальный адрес этого прерывания. Для этого используется функция 35h прерывания 21h.

;ah - содержит номер функции
mov ah, 35h

;al - указывает номер прерывания, адрес (или вектор) которого нужно получить

mov al, 21h
int 21h

;Теперь в es:bx адрес (вектор) прерывания 21h (es - сегмент, 
;bx - смещение)

;Обратите внимание на форму записи
mov word ptr Int_21h_vect, bx
mov word ptr Int_21h_vet+2,es

;Итак, адрес сохранили. Теперь переватываем прерывание:
mov ax,2521h
mov dx,offset Int_21h_proc ;ds:dx должны указать на наш обработчик (т.е. Int_21h_proc)
int 21h 

Прерывание 27h выходит в DOS (как 20h), при этом оставив нашу программу резидентной dx должен указывать на последний байт, оставшийся в памяти (это как раз метка Init). То есть в памяти остается от 0000h до адреса, по которому находится метка Init.

CEGS ends
end Start 

; --------------- S U B R O U T I N E ----------------------------------------------------------------------------
;НОВЫЕ ОПЕРАТОРЫ И ФУНКЦИИ ПРЕРЫВАНИЙ

ah = 35h         ;es=сегментный адрес вектора прерывания 
;bx = его смещение
ah=25h ;Ничего 
ds = сегмент нашего обработчика
dx = его смещение

ds:dx = последний байт, оставляемый в памяти. Ничего (выход в DOS)

; --------------- S U B R O U T I N E ----------------------------------------------------------------------------
РАБОТА С ФЛАГАМИ ПРОЦЕССОРА

pushf push flags - втолкнуть флаги -> Сохранить флаги
popf pop flags - вытолкнуть флаги -> Восстановить флаги

Int_21h_vect dd - define double word - определить двойное слово - четыре байта

dx,ax,es,ss -> 16 разрядный регистр - 2 байта (одно слово)
ah,dl,bh -> 8 разрядный регистра - 1 байт 

;загрузим в переменную Int_21h_vect одно слово (2 байта)
mov word ptr Int_21h_vect, ax

;загрузим 1 байт 
mov byte ptr Int_21h_vect, ah

; --------------- S U B R O U T I N E ---------------------------------

;ПРИМЕР НАПИСАНИЯ ОБОЛОЧКИ ПРОГРАММЫ КАК FAR MANAGER 

;СКЕЛЕТ БУДУЩЕЙ ОБОЛОЧКИ 
CEGM Segment ;название программы - CEGM (кода, процедуры)
assume cs:CEGM, ds:CEGM, es:CEGM, ss:CEGM ;сегментные регистры привязаны к единственному сегменту CEGM
org 100h ;отсчет начала смещения 100h (16-ная система h-hex) 

Begin_shell:
;Проверим видеорежим
call Check_video

;Выведем оообщение-приветсвие
mov ah,9
mov dx,offset Mess_about
int 21h

;Вызовем главную процедуру
call Main_proc

;Сюда мы вернемся, только когда пользователь решит выйти в DOS
int 20h

Файлы с процедурами;
Главная процедура, где будут происходить все действия 
include main.asm

Процедуры работы с дисплеем;
include display.asm

Процедуры работы с файлами;
include files.asm

Процедуры работы с клавиатурой;
include keyboard.asm

Тексты сообщения;
include messages.asm

ПРОГРАММА
Проверяем, утановлен ли режим видео 3 (т.е. текстовый 80х25)
mov ah,0Fh
int 10h
cmp al,3
je Ok_video ;проверка jump if equil 

Если установлен, то проверяем текущую видеостраницу, если нет то установим его функцией 0 прерывания 10h

mov ax,3         ;функция установки видеорежима
int 10h ;устанавливаем тектовый режим 80х25 и заодно чистим экран 


Пример
ah = 88h           ;номер функции
ds:si                 ;адрес строки, которую нужно вывести на экран (ds-сегмент, si-смещение)

; --------------- S U B R O U T I N E ---------------------------------
Часть обработчика прерывания 10h программ resid12.com

Int_10h_proc proc
pushf ;сохраним флаги в стеке, т.к. они изменяются

cmp ax, 8899h ;Проверим на повторную загрузку в память
jne Next_test         ;Если не проверка, то смотрим дальше 

;Меняем местами ah и al - признак того, что мы в памяти; что-то вроде 
;ответного сигнала
xchg ah,al 
popf ;выровняем стек
iret ;Выйдем из прерывания (вернемся в нашу программу)

;ax при возврате будет равен 9988h

Оператор xchg - источник, приемник, Exchange - обменять. Обмен регистров

Использование оператора xchg
mov ax,10h
mov bx,15h
xchg ax,bx ;теперь ax=15h, bx=10h

Регистр cs (Code Segment - сегмент кода) всегда содержит номер сегмента, в котором находится программа.
ip (Instruction Pointer - указатель инструкций) - смещение. 

cs:ip = 1234:0100h
[1234:0100h] mov ax,8899h
;После выполнения данной инструкции cs:ip=1234:0103h

[1234:0103h] int 10h
;Теперь cs:ip = сегменту/смещениб адреса (вектора) прерывания 10h,
;т.е. 0010:0400h

[1234:0105h] mov bx,10
Работаем дальше после того, как прерывание завершило свою работу. Выход из прерывания осуществляется с помощью команды iret ;выход из процедуры - ret 

8-бит регистр (al, ah, cl,...)
16-бит регистр (ax, dx, ...)
32-бит регистр (eax, edx, ecx...)
8-бит значение из памяти (byte ptr [xxxx])
16-бит значение из памяти (word ptr [xxxx])
6a 32-бит значение памяти (dword ptr [xxxx])

; --------------- S U B R O U T I N E ---------------------------------
Команды работы со строками
stos, lods, rep предназначены для работы с массивами данных 

lods загружает в регистр ax/al число, которое находится по адресу, 
указанному в регистрах ds:si, si автоматически увелич. на 1 или 2. 

lodsb - (b- byte, байт) загружает в al -> 1 byte
lodsw - (w-word, слово) загружает в ax -> 2 byte

sub - вычитание 
xor - иключающее ИЛИ. Это логическая команда. 
Но операторами sub и xor можно быстро и просто аннулировать регистры. 

; --------------- S U B R O U T I N E ---------------------------------
 ВИРУС
Наш вирус будет заражать только COM файлы. COM файлы загружются в первый 
свободный сегмент и их код располагатеся по спещению 100h.  

ПРОГРАММА ДО ЗАРАЖЕНИЯ
[1234:0100h] mov ax,34
[1234:0103h] mov dx,15 ;здесь может быть все, все что угодно 
[1234:0106h] add ax,bx
[1234:0108h] x и т.д.
[1234:0500h] int 20h         ;последний байт программы 
;далее идет уже паммть, не занятая под код или данные "файла-жертвы"

ПРОГРАММА ПОСЛЕ ЗАРАЖЕНИЯ 
;прыгаем до начало нашего вируса (заменили байты здесь)
[1234:0100h] jmp 0502h

[1234:0103h] mov dx,15  ;а это байты "файда-жертвы"
[1234:0103h] add ax,bx 

[1234:0502h] add ax,bx         ;а здесь уже начинается код нашего вируса
;здеь тело вируса. Делаем, что хотим 
;--------После того как вирус отработал-----------
;Восстановим первые два байта "файла-жертвы"
[1234:0700h] mov word ptr cs:[0100h], First_bytes_1

;Восстановим третий байт "файла-жертвы"
[1234:0705h] mov byte ptr cs:[0102h], First_bytes_2

;Теперь по адресу 100h первые два байта не jmp 502h, a mov ax,34 (т.е. 
;оригинальный код программы). 

;перейдем по адресу 100h т.е. передадим управление программе 
[1234:0709h] jmp 0100h

; --------------- S U B R O U T I N E ---------------------------------
Команда mov предназначена для работы с массивми данных. 

movs -> move string - скопировать строку, копираование (массива) 

При этом ds:si указывает на то, откуда брать данные es:di куда их копировать
cx - количество пресылаемых байт/слов 

mov cx,10 ;количество переселаемых байт
mov si, offset Str 1                 ;откуда будем брать
mov di, offset Str 2                 ;куда копировать
rep movsb ;пересываем побайтно т.е. movsb
;Теперь Str1=Str2

; --------------- S U B R O U T I N E ---------------------------------
Пример использования move 

mov cx,5 ;количество пересылаемых слов (два байта)
mov si,offset Str1 ;откуда будем брать
mov di,offset Str2 ;куда копировать 
rep movsw ;Пересылаем 

;Теперь Srt1=Str2
Str1 db '1023456789'
Str2 db '9876543210'

ПРИМЕР ПРЫЖКА НА ДР. ПРОРАММУ
JMP DWOD PTR CS:[OFF_MOVE]

; --------------- S U B R O U T I N E ---------------------------------
МОДЕЛИ ПАМЯТИ 

Модели памяти определяет структура и способ расположения кода и данных программы. 
Модели бывают: 
TINY - "крошечная" модель, где код программы, ее данные и стек располагаются в одном секменте, при этом используется 16-битная адресация (т.е. размер программы не может превышать 64 Кбайта). Эта модель памяти используется в файлах типа COM, компактна, и очень удобна для написания небольших программ на ассемблере (например резидентов). 

COMPACT - "КОМПАКТНАЯ"  модель где код программы размещается в одном сегменте, а данные могут занимать один сегмент и более. В этом случае обращение к данным происходит с указанием сегмента и смещения.

MEDIUM - "средняя модель" где код размещается в нескольких сегментах, а данные в одном. Сл-но к данным можно обращаться, используя только смещения, а к коду (вызов подпрограмм, безусловные переходы и т.п.) не только смещение, но и сегмент.

LARGE HUGE - "большая" и "огромная" модели, где и код и данные могут занимать несколько сегментов.

FLAT - "плоская" модель, где код, данные и стек размещаются в одном секменте (как и в модели TINY), но при этом использутеся 32-бит адресация. Один сегмент может имет размер до 4 Гбайт. Использутся как правило в программах под Windows.

.model     ;модель памяти

.286     ;указывает ассемблеру, что будут использоваться инструкции (команды, оператора) 
           ;для процесссора 80286 

Пример использовнаия директивы .model
Указываем пограмме-ассемблеру тип модели (TINY). Дикертиву ASSUME в таком случае  можно опустить 

.model TINY 
CEGM segment ;Однако имя сегмента и счетсик (ORG) задаются. 
org 100h 
Begin:
mov ah,9
mov dx, offset Message
int 21h
ret
Message db "Hello world!$"
;Данные и стек расположены в том же сегменте, что и код. Вершина стека 
;изначально равра 0FFFFh того сегмена, куда загрузилась программа

CSEG ENDS
END BEGIN 

; --------------- S U B R O U T I N E ---------------------------------
SHL -ИСТОЧНИК, ПРИЕМНИК Shift left - сдвиг всево -> сдвиг бит 
SHR  - ИСТОЧНИК ПРИМЕМИК Shift right - сдвиг вправл -> сдвиг бит 
MUL BL - Multiplex - умножение Умножение al на  bl 

Пример
mov ax, 100b 
shl ax,1 ;Теперь в ax число 1000b 

mov ax,100
shr ax,1 ;Теперь в ax число 10b 

mov bl, 5
mov bl, 2
mul bl         ;Теперь в ax число 10 

; --------------- S U B R O U T I N E ---------------------------------
СПОСОБЫ ПЕРЕДАЧИ УПРАВЛЕНИЯ

jmp dword ptr cs:[Int_21h_vect]
dword ptr - ;означает, что надо прыгнуть используя не только смещение, но и 
;сегмент (сегмент:смещение), которые находятя в переменной Int_21h_vect
;[] - указывают на, что что нужно прыгнуть но тот адес, который находится
;в переменной [Int_21h_vect]
jmp dword ptr ;данная команда назыв "дальний" jmp с переодом в другой сегмент 

call dword ptr cs:[Int_21h_vect]                  ;вызыов ближайщей процедуры near 
call Near_proc ;вызов ближайшей процедуры 

jmp dword ptr         ;называется дальний 
call dword ptr cs:[Int_21h_vect]                 ;вызов процедур расположенной в другом сегменте
call Near_proc ;вызов ближней процедуры 

ПРИМЕР ВЫЗОВА БЛИЖНЕЙ ПРОЦЕДУРЫ 
Вызов ближней процедуры 
;Предположим, что стек пустой (ss=1234h, sp=0FFFFh)
[1234:0100h] mov ax, 0A0Bh
[1234:0103h] call Our_proc ;Вызываем процедуру Our_proc 
[1234:0105h] mov dx,123h
[1234:0200h] Our_proc proc
[1234:0200h] mov dx,offset Message 

;Выходим из процедуры (переходим на адрес 1234:0105h)
[1234:0250h] ret
[1234:0250h] Our_proc endp

ПРИМЕР ВЫЗОВА ДАЛЬНЕЙ ПОДПРОГРАММЫ
;Заносим сперва смещение 
mov word ptr [New_proc], 0400h
;Затем сегмент
mov word ptr [New_proc+2],3456h
;Вызываем процедуру 
call dword ptr [New_proc]

New_ro dd?? ;Переменная для хранения адреса дальней процедуры (2 байта)

ВЫЗОВ БЛИЖАЙШЕЙ ПРОЦЕДУРЫ
[1234:0200h] call Near_proc ;Вызов ближйшей процедуры 
;Правильный выход из ближней процедуры (процедуры, которая располагается 
; том же сегменете, что и программа, ее вызывающая)
[1234:6789h] ret
[1234:6789h] Near_proc endp

ВЫЗОВ ДАЛЬНЕЙ ПРОЦЕДУРЫ 
[1234:0200h] call dword ptr cs:[New_proc]

;Дальнаяя процедура New_proc (находится в другом сегменте)
[3456:0300h] New_proc

;Правильный выход из дальней процедуры (процедуры, которая находится
;в другом сегменте, в отличие от программы ее вызывающей)
[2345:0534h] retf
[3456:0534h] New_proc endp

РЕЗЮМЕ
RET достает из стека только смещение для возврата, процедура должна находится  в том же сегменте, из которого ее вызывают (ближняя процедура - near (по умоланию).

RETF достает из стека сегмент и смещение, процедура может находится в любом сегменте  независимо от того, откуда ее вызывают (дальняя процедура - far или dword ptr) .
 
IRET достает из стека сегмент, смещение и адрес флагов. Используется для выхода из прервания. 

ОПЕРАТОР IREF
pushf ;Заносим в стек флаги
call dword ptr [Int_21h_vect]                 ;Вызываем дальнюю процедуру

ЛОГИЧЕСКИЕ КОМАНДЫ ПРОЦЕССОРА
AND
OR
XOR

ОПЕРАТОР OR (ИЛИ)
Служит для включения определенных битов (не байтов!) в регистре, 
переменной или в памяи 
mov ax,1010b
or ax,1111b

ОПЕРАТОРА AND (И) служит для исключения битов 
mov ax, 1010b
and ax, 0101b

ОПЕРАТОР XOR (ИСКЛЮЧАЮЩЕЕ ИЛИ) используется в основном для кодирования данных
mov ah,1010b
xor ah,1100b

ПЕРЕМЕННЫЕ ОБЪЯВЛЮЯТСЯ ДИРЕКТИВАМИ
db (однобайтная переменная), 
dw (переменная длиной в одно слово), 
dd (переменная длиной в двойное слово) и т. д. 
Для загрузки переменной в указатель применяется либо команда lea, либо mov с директивой offset.

СЕМЕЙТВО КОМАНД условного перехода jx проверяют условие x и, если оно истинно, совершают переход (jump) по указанному адресу. Например, je выполняет переход, если числа равны (Jump if Equal), а jne — если эти числа не равны (Jump if Not Equal). Команды jb/ja работают с беззнаковыми числами, а с jl/jg — со знаковыми. Любые два не противоречащих друг другу условия могут быть скомбинированы друг с другом. Например, команда jbe осуществляет переход, если одно беззнаковое число меньше другого или равно ему. Безусловный переход осуществляется командой jmp.

Большинство функций API операционный системы Windows придерживаются комбинированного соглашения stdcall, при котором аргументы заносятся в соответствии с соглашением C.

Вызов функций API операционной системы
PUSH offset LibName ;                 // Засылаем в стек смещение строки
CALL LoadLibrary ;                     // Вызов функции
MOV h, EAX ;                              // EAX содержит возращенное значение

.text - (СЕКЦИЯ КОДА) эта секция содержит исполняемый код. Благодаря 32-битной плоской адресации содержимое аналогичных секций всех oбъектных файлов, подаваемых на вход линкера, собирается в одной секции .text исполняемого PE-файла.
  
.data - (СЕГМЕНТ ДАННЫХ)содержит инициализированные и глобальные переменные. 

.idata - содержит данные об импортируемых приложением функциях, то бишь таблица импорта. Эта таблица состоит из 1) массива с описанием используемых DLL'ок, 2) двух массивов с адресами импортируемых функций и  3) массива имен импортируемых функций. 
  
.rdata - содержит данные, доступные только для чтения, как-то: литеральные строки, константы, отладочную информацию.

DATA XREF: sub_40100+62 расшифровывается следующим образом: перекрестная ссылка (XREF) на данные (DATA), ведущая к коду, расположенному по смещению 0x62 относительно начала функции sub_40100. Для быстрого перехода в указанное место достаточно лишь подвести курсор в границы sub_401000+62 и нажать клавишу <ENTER> (или же выполнить двойной щелчок мышью).

Точки останова на функции API
Точки останова (они же breakpoints, в просторечии называемые "бряками")
Наибольшей популярностью пользуются точки
останова на API-функции. 
GetWindowTextA - Чтение содержимого окна часто
CreateFileA, - открытие файла
LoadLibraryA - загрузка динамической библиотеки 

int WINAPI WinMain
HINSTANCE hInstance, // Handle to current instance
// Дескриптор текущего экземпляра
HINSTANCE
hPrevInstance,
// Handle to previous instance
// Дескриптор следующего экземпляра
LPSTR lpCmdLine, // Pointer to command line
// Указатель на командную строку
int nCmdShow // Show state of window
// Статус окна

BOOL WINAPI DllMain(
HINSTANCE hinstDLL, // Handle to DLL module
// Дескриптор модуля DLL
DWORD fdwReason, // Reason for calling function
// Причина вызова функции
LPVOID lpvReserved // Reserved
// Зарезервировано
Copy_scr - коприрование в буфер
Restore_scr - восстановлние 

scas - Scan string сканирование строки. Поиск символа в массиве
movs, stos - поиск символа в массиве 
scasb - поиск первого попавшегося байта
scasw - поиск попавшегося слова (двух байт) 

repne - repeat if not equal (повторять если не равно) сканирует строку (массив) до тех  пор, пока символ, расположенный в al/ax не будет в этой строке (массиве) найден. Оператор используется для поиска первого символа. 

repe - repeat if equil (повторять если равно)

je Label - (переход на метку label если байт найден)

ПРИМЕР ИСПОЛЬЗОВАНИЯ ОПЕРАТОРА MOVS

Пример 1
mov cx,10 ;количество пересылаемых байт
mov si, offset Str1 ;откуда будем брать 
mov di, offset Str2 ;куда копировать 
rep movsb ;Пересылаем побайтно т.к. movsb

Пример 2
mov cx, 5 ;количество пересылаемых слов (два байта)
mov si, offset Str1 ;откуда будем брать
mov di, offset Str2 ;куда копировать
rep movsw ;Пересылаем пословно (по два байта) 

; --------------- S U B R O U T I N E ---------------------------------
ВИРУС
СТРУКТУРА ВИРУСА 

CSEG Segment         ;название программы, алгоритма
assume cs:CEGM, ds:CEGM, es:CEGM, ss:CEGM ;сегментные регистры привязаны к единственному сегменту CEGM
org 100h ;отсчет начала смещения 100h (16-ная система h-hex) 
Start:
;Переходим на метку инициализации. Нам нужно будет перехватить прерывание
;21h, а также оставить программу резидентной в памяти. 
;Ниже идет, собственно, код разработчика прерывания 21h (он будет резидентный)
;После того как программа выйдет, процедура Int_21h_proс останется в памяти и 
;будет контролировать функцию 09 прерывания 21h. 

Int_21_proc proc 
cmp ah,9 ;Прверим: это функция 09h?
je Ok_09 

;Если нет, перейдем на оригинальный обработчик прерывания 21h. Все. На метку Ок_09
;программа уже не вернется 
jmp dword ptr cs:[Int_21h_vet]

Ok_09:
push ds ;Сохраним регистры
push dx
push cs ;Адрес строки должен быть в ds:dx
pop ds 

;Выводим нашу строкку [My_string] вместо той, которую должна была вывести программа,
;вызыващая 21h-е прерывание 

mov dx,offset My_string
pushf ;Эта инструкция здесь необходима 
call dword ptr cs:[Int_21h_vect]

pop dx ;Восстановим использованные регистры
pop ds
iret         ;Продолжим работу (выйдем из препрывания) 


CSEG ends ;конец алгоритма
end Start

; --------------- S U B R O U T I N E ---------------------------------
mul bl Multiplex - умножение Умножение al на bl 

ОПЕРАТОР TEST
TEST - источник, приемни, тест, проверка.Проверка одного и более битов. 

ПРИМЕР1
mov ax, 101000001b
test ax,1 ;Проверим, равне ли нулевой бит единице
jnz Ravno ;Переход если равень 

ПРИМЕР2
mov cl, 101000001b
test cl,1000b ;Проверим, равне ли третий бит единице
jz Ne_Ravno ;Переход если НЕ равень 


ПРИМЕР3
mov ax, Other ;Получим дополнительную информаци 
test al,1 ;Нулевой бит 0?
jz No_copyscr ;Если так, то копировать экран не нужно


 ; --------------- S U B R O U T I N E ---------------------------------
 КОМАНДЫ БЕЗУСЛОВНОГО ПЕРЕХОДА 
 JB (JUMP IF BELOW)  ПЕРЕХОД ЕСЛИ ПРИЕМНИК МЕНЬШЕ ИСТОЧНИКА
 JBE (JUMP IF BELOW OR EQUAL) ПЕРЕХОД ЕСЛИ МЕНЬШЕ ИЛИ РАВНО
 JNB (JUMP IF NOT BELOW) ПЕРЕХОД ЕСЛИ НЕ МЕНЬШЕ (РАВНОСИЛЬНА JAE)
 JA (JUMP IF ABOVE) ПЕРЕХОД ЕСЛИ БОЛЬШЕ
 JAE (JUMP IF ABOVE OF EQUAL) ПЕРЕХОД ЕСЛИ БОЛЬШЕ ИЛИ РАВНО
 JNA (JUMP IF NOT ABOVE)  ПЕРЕХОД ЕСЛИ НЕ БОЛЬШЕ (РАВНОСИЛЬНА JBE)
  
 Stc Set carry flag - установить флаг переноса 
 Clc Clear carry flag - сбросить флаг переноса 
 std Set destination flag - установить флаг направления 
 cld Clear destination flag - сбросить флаг направления 

In computer programming, a subroutine is a sequence of program instructions that perform a specific task,  packaged as a unit. This unit can then be used in programs wherever that particular task should be performed.  Subprograms may be defined within programs, or separately in libraries that can be used by multiple programs. In different programming languages, a subroutine may be called a procedure, a function, a routine, a method, or a subprogram.

Комментариев нет:

Отправить комментарий