Асемблер це просто! Вчимося програмувати випуск n 10 (bler) розсилка

Чому я з пива-то почав? Так ось чому: зараз є чотири хороші новини:

Я також дякую всім, хто надсилав мені пропозиції з приводу працевлаштування. Любі мої! Низький вам уклін і море подяки.

Якщо у Вас немає доступу в Мережу, то напишіть мені лист з просьбоей вислати той чи інший випуск або все разом:

А ось нижче лист від Леоніда. Подібних листів прийшло багато, тому я відповім на одне як всім:

Добрий день, Олег!

Хотілося б зайнятися ассемблером, але не знаю з чего.Подскажі з чого почати (з нуля); якщо є щось в електронному вигляді, то, якщо не важко, вийшли.

З повагою Леонід.

Програма з минулого випуску.

Тепер з приводу попереднього випуску. Що у нас була за програма? Так! Вона завантажувала саму себе в пам'ять. Тобто поверх себе (поверх свого коду). Я не дарма просив Вас назвати її саме less009.asm. Оскільки якщо програма не знайде файл з такою назвою (* .com), то вона просто вийде, при цьому видасть звуковий сигнал. Одна дівчина, яка цікавиться програмуванням на Асемблері (так-так, дорогі мої! В наших рядах є жінки, чому я дуже радий!), Назвала роботу програми "чортівнею". Насправді, нічого складного в ній немає. Сподіваюся, Ви зрозуміли, що в Асемблері можна витворяти неймовірні речі, які на мовах високого рівня (Бейсік, С, Паскаль) недоступні.

; Програма виконує запис самої себе в те місце пам'яті, куди вона

assume CS: CSEG, DS: CSEG, ES: CSEG, SS: CSEG

mov dx, offset File_name; відкриваємо файл

call Open_file; за допомогою спец-процедури (див. нижче).

jc Error_file; Перехід на мітку Error_file при невдачі.

mov bx, ax; Зберігаємо ідентифікатор файлу і

mov cx, offset Finish-100h; Записуємо довжину нашої програми (к-ть читаються байт),

mov dx, offset Begin; і читаємо файл в пам'ять,

call Close_file; Закриваємо файл за допомогою спец-процедури (див. Нижче).

mov ah, 9; Виводимо повідомлення про вдале завершення.

mov dx, offset Mess_ok

; Якщо файл з вказаним ім'ям не знайшли (File_name db 'less009.com', 0), то піщім і виходимо. (Прим. - О. К.)

Open_file proc; Процедура відкриття файлу для читання,

cmp Handle, 0FFFFh; в якій з'ясовується чи відкритий файл,

jne Quit_open; і якщо не відкрито - відкриваємо його.

stc; Встановлюємо прапор переносу в 1, необхідний

ret; для підтвердження факту відкриття файлу (для jc).

Handle dw 0FFFFh

Close_file proc; Процедура закриття файлу,

cmp Handle, 0FFFFh; за умови, що він був відкритий.

File_name db 'less009.com', 0

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

; типу writeln або puts ().

Детальніше ми розглянемо принцип роботи подібних програм пізніше.

Більшість з вас проголосувало за вивчення Ассемблера таким чином:

швидко DOS, а потім Windows. Я вважаю, що це цікавіше і доцільніше буде, ніж просто вивчити DOS, або відразу перейти до Windows. Таким чином, ми починаємо вивчати DOS.

Що ж стосується програми, яку ми будемо писати, паралельно вивчаючи Асемблер, то результати такі:

1. Оболонка типу Norton Commander;

На перше місце все ж вийшла оболонка, але не на багато обігнавши вірус.

Сьогодні ж у нас експериментальний випуск. Спробуємо проходити тему швидше, ніж треба. Якщо щось не засвоїте - пишіть. Заходьте на форум на сайті. Пишіть мені. В кінці розсилки я спеціально проводжу опитування.

Що таке вірус? Вірус - це програма, написана, як правило, на Асемблері (хоча є віруси, написані на Pascal, С і Visual Basic). Ця програма може сама розмножуватися, заражаючи інші програми без участі програміста, який сам же і написав цей вірус. Як так може бути? Елементарно!

Писати вірус на Асемблері - мила справа. Свого часу я писав віруси як резидентні (постійно знаходяться в пам'яті), так і нерезидентні. Більш того, я писав і антивіруси (проти своїх же вірусів, природно).

Перш ніж перейти до вивчення структури вірусу, я хотів би попередити Вас про кримінальну відповідальність за поширення вірусоподібних програм. Якщо Ви напишіть вірус, а потім випустіть його "в люди", то Вас зможуть відправити в "місця не настільки віддалені" (по Російським законам); наприклад, на Колиму.

Хто пише віруси? Так все кому не лінь! Перш за все - це програмісти, які тільки-тільки вивчили Асемблер, і не бачать іншої можливості, як тільки написати якийсь вірус і нашкодити своєму другові, сусідові і т.д. тим самим проявивши себе. Наприклад, у знайомого стоїть великий Пень-433, а у Вас - маленька "трійка". І Ви горите бажанням його Пень "заламати".

Тепер уявімо іншу ситуацію: у фірми X є конкурент - фірма Y. Як зробити так, щоб на час фірмі Y завдати клопоту? А чому б їх комп'ютери не заразити вірусом "власного виробництва", який такого-то числа або при таких-то обставин видаляв би всю інформацію на вінчестері? Пишеться вірус співробітником фірми X, а потім він (вірус) заноситься в комп'ютер до конкурента. І все! Як правило заражаються комп'ютери не тільки фірми Y, а й інші (співробітник переписав заражений файл і пріес до себе додому, і в нього переписав цей же файл знайомий і т.д.).

Тепер розглянемо структуру вірусу і принцип його роботи. Мета всього цього - навчити Вас розпізнавати віруси і розвіяти страх перед ними.

Що повинен робити вірус? Перш за все - визначити, завантажений він з якогось файлу або це його перша завантаження (далі Ви зрозумієте, про що йде мова). Потім знайти перший-ліпший файл, перевірити його, чи заражений вже він чи ні, якщо так, то шукати наступний, а якщо немає, то заразити його. Все це відбувається дуже швидко і для користувача практично непомітно.

Скільки займає вірус в пам'яті? Все залежить від фантазії програміста (що він хоче зробити з компьтером / файлами). Середній розмір вірусу - 500 - 600 байт. Хоча є умільці, у яких вірус займає 100 - 150 байт, а є і такі, у яких найпростіший вірус займає 1,5 - 3 і більше кілобайт.

Що може вірус? Все що завгодно! Наприклад, видалити всю інформацію з вінчестера за 0,5 - 1 секунду (за принципом роботи Fdisk), спалити монітор, фізично зіпсувати вінчестер і навіть вбити користувача (хоча такого не зустрічав поки)! Все залежить від фантазії програміста.

Який вірус ми будемо вивчати? Ми будемо розглядати нерізедентний вірус, що заражає * .com-файли (найпростіший). Що він буде робити? Я думаю, нічого особливого, крім як розмноження і створення будь-якої незначною перешкоди для користувача.

Як оформити вірус? зазвичай:

assume cs: CSEG, ds: CSEG, es: CSEG, ss: CSEG

; Тут знаходиться тіло вірусу.

Тобто формат звичайного * .com-файлу, який Вам вже відомий. Можна створити і * .exe-файл, проте, його розмір буде більше.

Я думаю, що на сьогодні з вірусом вистачить. Тим більше, що за результатами ваших опитувань, вірус - це не те, на що б Ви хотіли зробити акцент при вивченні Ассемблера.

Приступаємо до найскладнішого розділу. Буде дійсно складно. Хто зможе розібратися - буде справжнім героєм!

Резидентна програма (резидент) - програма, яка постійно знаходиться в пам'яті. Прикладом резидента є драйвер миші, Norton Guide, всілякі антивіруси, які стежать за тим, що робить та чи інша програма і повідомляють про її діях користувачеві тощо.

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

Переривання - це свого роду процедура (підпрограма), яка має не назву (наприклад, print_string), а номер. У комп'ютері є 256 різних номерів переривань. Деякі номери зарезервовані BIOS (ПЗУ) комп'ютера (наприклад, 16h; пам'ятайте: mov ah, 10h / int 16h?) Або операційною системою (MS-DOS, PC-DOS, OS / 2) (наприклад, 21h: mov ah, 9 / mov dx, offset String / int 21h).

Проте, нічого не заважає програмісту перехопити, скажемо, 21h переривання, тим самим контролювати хто і що робить з ним.

Ну наприклад. Виведемо на екран рядок:

mov dx, offset Our_string

Our_string db 'Привіт! $'

; Уявімо, що це шматок нашого обробника 21h переривання.

; тут передаємо управління "справжньому" 21h.

mov dx, offset My_string

Тут ми перевіряємо, чи викликається функція виведення рядка на екран (09) або будь-яка інша. Якщо викликається інша функція (наприклад, 3Dh), то ми просто віддаємо управління оригінальному обробника.

Що ж таке обробник переривання. Це процедура, постійно (або на час) знаходиться в пам'яті, яка приймає управління першої, робить що хоче, а потім передає управління оригінальному обробника (тобто процедурі, яка вже перебувала в пам'яті до завантаження нашого обробника). Та може також виконати деякі дії, а потім передати управління іншій оброблювачу і т.д.

Якщо що-небудь не зрозуміло - не впадайте у відчай! Це дійсно дуже складно! Дуже скоро все стане на свої місця.

Тепер перейдемо до обробника (читайте уважно опису після крапки з комою):

assume cs: CSEG, ds: CSEG, es: CSEG, ss: CSEG

; Переходимо на мітку ініціалізації. Нам потрібно буде перехопити переривання 21h, а також залишити програму резидентної в пам'яті

; Нижче йде, власне, обробник 21h переривання (він буде резидентний). Після того, як програма вийде, процедура Int_21h_proc залишиться в пам'яті і буде контролювати функцію 09 переривання 21h. Він у нас буде жирним.

jmp dword ptr cs: [Int_21h_vect]; Якщо немає, прейдем на оригінальний обробник переривання 21h. Усе. На мітку Ok_09 програма вже не повернеться

Що таке прапори ви пам'ятаєте? Про всяк випадок розглянемо коротко на прикладі ще раз:

Тут після виконання рядки (1) встановиться / скинеться прапор нуля. У рядку (2) перевіряємо цей самий прапор. Якщо він встановлений, значить команда порівняння вірна (тобто AX = 23). Якщо ж не встановлено, то AX <> (Чине дорівнює) 23.

Тепер зверніть увагу на самий початок процедури Int_21h_proc. Що ми бачимо:

Ми порушуємо роботу програми (змінюємо прапор нуля). Це може привести до досить-таки серйозних змін в ході роботи програми, яка викликала 21h переривання. Для цього, власне, ми і зберігаємо прапори в стеці. Сподіваюся, ви зрозуміли, що в обробнику переривання (в нашому випадку - Int_21h_proc) необхідно зберігати ВСЕ використовувані регістри, включаючи регістр прапорів.

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

Дана змінна може зберігати подвійне слово (D efine D ouble word - визначити подвійне слово) (чотири байти). Згадуємо, що один 16-і розрядний займає 2 байта (одне слово) (DX, AX, ES, SS і т.д. але не AH, DL, BH - це 8-й розрядні регістри, які займають один байт!).

Якщо ми хочемо завантажити в дану змінну слово (два байта), то нам необхідно вказати це в такий спосіб:

mov word ptr Int_21h_vect, ax

Якщо ж ми хочемо завантажити один байт, то пишемо так:

mov byte ptr Int_21h_vect, ah

Згадуємо, що word - це слово, а byte - це байт. Що-небудь прояснилося?

Потім створіть найпростішу програму, яка буде виводити на екран деяку рядок шляхом виклику 09 функції 21h переривання. Наприклад, так:

assume CS: CSEG, DS: CSEG, ES: CSEG, SS: CSEG

mov dx, offset String

String db 'My string. $'

Запускаємо спершу Програму N 01. Після того, як він повернеться в DOS (в Norton Commander, DOS Navigator, Far тощо. Оболонки), запускайте Програму N 02. Що ви побачите?

Тепер запустіть Програму N 02 в отладчике. Заходьте сміливо "всередину" 21h-ого переривання. Що ви бачите тепер?

Ну що, дорогі мої! Складно?

1. Всі уважно прочитав кілька разів, але нічого не зрозумів.

2. Погано пояснюєш. "Дійшло" на третю добу.

3. "Дійшло" насилу. Бажано пояснювати детальніше. А так все нормально.

4. Важко, але цікаво. Продовжуй в тому ж дусі!

5. Все отлично! Класно пояснюєш!

6. елементарщину! Швидше б до Windows перейти.

На сьогодні все! Оболонку розглянемо на наступному тижні (байт не вистачить). Вдалого програмування вам!