1. Вы находитесь в архивной версии форума xaker.name. Здесь собраны темы с 2007 по 2012 год, большинство инструкций и мануалов уже неактуальны.

Ассемблер. Уроки для новичков от Robo

  1. Ассембли. Урок I - Вызовы API

    Привет. Итак приступим к делу, для этого нам нужно скачать какой-нибудь компилятор ассемблера, качайте или FASM или MASM, так как отличия в синтаксисе минимальны. Скачать их можно с моей странички - www.robo9.xaker.name в соответствующем разделе. Лучше конечно скачать FASM, так как этот компилятор нравиться мне больше остальных и обьяснять я буду именно на нём.

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

    Создадим простой текстовый файлик и назовём его "first.asm" и начинаем программировать:

    Код:
    	include 'win32ax.inc'
    
    	   .code
    
      		start:
    
                    invoke  ExitProcess,0       ; вызываем функцию ExitProcess c параметром 0 (нуль)
    
               .end start 
    Что делает этот код? Да ничего... Если мы его скомпилируем то получим полноценную программу которая просто завершает сама себя. Компилируем:

    fasm.exe first.asm

    Итак, вы попытались скомпилировать... Но не получилось, а всё потому что компилятор не знает где находиться файл-инклудник - "win32ax.inc". Необходимо ему явно указать этот файл для этого меняем код программы, например вот так:

    Код:
    	include 'D:\FASM\include\win32ax.inc'
    
    	   .code
    
      		start:
    
                    invoke  ExitProcess,0       ; вызываем функцию ExitProcess c параметром 0 (нуль)
    
               .end start
    
    Теперь всё скомпилируеться отлично, но чтобы это не писать каждый раз, можно задействовать переменные среды, присвоив например переменной %inc% путь "D:\FASM\include". Но этим мы займемся в следующем туториале, так как в этом я собираюсь показать как вызываеться функция Windows API (какой и являеться ExitProcess).

    Кстати invoke - это макрос, который обьявлен в инклуднике win32ax.inc. Он позволяет нам вызывать функции привычным образом как например в С++ или Delphi. Без него мы будем писать в следующих туториалах. Короче усвойте что invoke это вызов функций (но только на первый туториал, ну или на все если в будущем вы собираетесь программировать именно с его помощью).

    Теперь давайте добавим в нашу программу ещё одну функцию - MessageBox:

    Код:
    	include 'D:\FASM\include\win32ax.inc'
    
    	   .code
    
      		start:
    		
    		invoke  MessageBox,HWND_DESKTOP,"Hallo Xaker.Name","Caption",MB_ICONASTERISK
    		
                    invoke  ExitProcess,0       ; вызываем функцию ExitProcess c параметром 0 (нуль)
    
               .end start
    
    Первый параметр функции MessageBox являеться дескриптор окна-родителя нашего окошка, в качестве него мы передаём константу HWND_DESKTOP - дескриптор Рабочего Стола.
    Второй параметр - адрес на текст самого окошка. Возникает вопрос - почему же мы не пишем: invoke MessageBox,HWND_DESKTOP,offset Message....? Да потому что, макрос invoke достаточно универсален, чтобы принимать в параметре просто текст... Подробнее обьясню в следующих уроках.
    Третий параметр - заголовок окна, то есть его адрес.
    Ну а четвёртый параметр - стиль окна, у нас это MB_ICONASTERISK то есть окошко с восклицанием.

    Кстати дополнительную информацию об API - можно получить либо на MSDN либо из любой справки Windows SDK, которая поставляеться с любым продуктом Borland. Вот и написали и разобрали вызов функций и написали полноценное приложение. Всё, до следующего туториала, всего хорошего...

    (c) Robo
     
    4 пользователям это понравилось.
  2. Ассембли. Урок II - Циклы и условные переходы

    Ассембли. Урок II - Циклы и условные переходы

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

    Код:
    include 'D:\FASM\include\win32ax.inc'
    
               .code
    
                    start:
    
                         mov esi,5d				; кладём в регистр esi число 5
    
                             @@loop:			; обьявили метку
    
                                 invoke MessageBox,0,0,0,0	; вызываем окно
    
                                    dec esi			; уменьшаем счётчик
    
                                    cmp esi,0		; сравниваем esi c нулём (проверяем не кончился ли счётчик)
    
                                    ja @@loop       	; и если число в esi превышает 0 (нуль) то прыгаем на метку @@loop
    
                                 invoke  ExitProcess,0	; ну а если равно то выходим из программы
    
                   .end start
    
    Тут наверное стоит пояснить что метка @@loop - так написанна для удобства и только для этого. Есть ещё понятие анонимных меток - о них мы поговорим в следующих уроках. Итак из комментариев в коде я думаю всё ясно. Мы просто обьявили регистр esi как счётчик, затем мы вызываем окошко и уменьшаем счётчик на 1 (dec - уменьшить на 1). Сравниваем счётчик с нулём, так мы проверяем, не кончился ли счётчик, и если не кончился - переходим на метку @@loop. Поясню, что JA - Jump if Above то есть переход если больше. Так и получаеться что пока в esi больше нуля то мы "бегаем по коду" и выполняем вызов окна. Как только счётчик установлен в 0 (нуль) - выполнение программы прекращаеться, то есть выполняеться ExitProcess.

    Кстати в этой программе мы использовали и цикл и условный переход. Но давайте превратим этот код в более привычный вид для программистов на C++ и Delphi:

    Код:
    include 'D:\FASM\include\win32ax.inc'
    
               .code
    
                    start:
    
                         mov esi,5d
    
                             @@loop:
    
                                 invoke MessageBox,0,0,0,0
    
                                    dec esi
    
                                    .if esi = 0
    
                                        invoke  ExitProcess,0
    
                                    .endif
    
                              jmp @@loop
               .end start
    
    Тут уже попонятнее да? Появился привычный нам всем if. Как вы уже знаете после if выполняеться код если условие верно. То есть если у нас esi = 0, то выполняеться ExitProcess. Тут всё понятно и так. Если не понятно - всегда рад ответить на ваши вопросы.

    И вот только сейчас я вспомнил что я обещал на прошлом уроке показать как использовать переменные среды. Но я не буду этого делать. А почему? Да потому что я нашёл видео по этому делу:

    http://sulaiman.netadvant.com/video/fasm-05.rar . Но для его просмотра нужно скачать кодек: http://sulaiman.netadvant.com/video/VMware-moviedecoder-5.0.0-13124.exe

    (c) Robo
     
    2 пользователям это понравилось.
  3. Ассембли. Урок III - Сравнения и переходы (более подробно)

    Ассембли. Урок III - Сравнения и переходы (более подробно)

    Привет. На этом уроке поговорим про операторы cmp & условные переходы более подробно. Для начала обратите внимание на таблицу условных переходов. Вы уже видели нечто подобное на прошлом уроке:

    [​IMG]

    Теперь давайте посмотрим на практике. Есть код:

    Код:
    1)	mov eax,32		; в EAX 32h
    
    2)	mov ebx,33		; в EBX 33h
    
    3)	cmp eax,ebx		; сравниваем EAX c EBX
    
    4)	jne metka		; Если не равны то прыгаем на metka
    
    5)	sub eax,eax		; иначе обнуляем EAX
    
    metka:
    
    6)	invoke ExitProcess,0	; завершаем процесс
    
    Разберём каждую инструкцию:

    1) mov - инструкция, которая присваивает значения. В данном случаи мы присваиваем регистру EAX число 32h (hex)

    2) Аногогично, только теперь регистру EBX присваиваеться 33h

    3) cmp - оператор сравнения (Compare - сравнивать). Сравнивает EAX c EBX и взависимости от результата выставляет соответствующие арифметические флаги (у нас ZF, SF, CF - но не подумайте что это все флаги!)

    4) Наш условный переход, чтобы его понять обратимся к таблице. Смотрим тип операндов - любые, значит не имеет значения, со знаком числа или без. Далее смотрим критерий условного перехода - 1операнд НЕ РАВЕН 2операнду. И третие - смотрим значение флага, в данном случаи это флаг "нуля" (ZF - Zerro Flag). Итак из таблицы видно что, чтобы мы прыгнули на метку - регистры EAX & EBX не должны быть равны и флаг нуля устанавливаеться в 0(нуль). То есть если они не равны - мы прыгаем на метку "metka"

    5) Так как переходу быть - процессор не выполняет эту инструцкию. Она предназначена для вычитания. То есть если бы перехода не было она бы вычла из EAX, EAX (значения) - тем самым обнулив его.

    6) Уже до боли знакомый вам вызов функции API ExitProcess, который просто завершит программу.

    Если бы мы в 4) пункте написали бы не JNE a JZ то мы бы не прыгнули на метку, так как регистры EAX & EBX не равны между собой.

    Для полноты всей картины давайте воспроизведём всё выше описаное в полноценную программу:

    Код:
    include 'D:\FASM\include\win32ax.inc'
    
    .code
    
    start:
    
            mov eax,32              ; в EAX 32h
    
            mov ebx,33              ; в EBX 33h
    
            cmp eax,ebx             ; сравниваем EAX c EBX
    
            jne metka               ; Если не равны то прыгаем на metka
    
            sub eax,eax             ; иначе обнуляем EAX
    
    metka:
    
            invoke ExitProcess,0    ; завершаем процесс
              
    .end start              
    
    Вот и весь урок. Можно эксперементировать задавая разные значения регистрам и изменяя прыжок - так вы быстрее поймёте. Есстественно нужно это делать в отладчике. Возьмите Olly. Кстати вот этот наш кусок кода в отладчике выглядит следующим образом:

    [​IMG]

    Красная стрелочко означает что сейчас произойдёт переход, и я ещё там написал что флаг нуля = 0 (нуль), чтобы не постить весь экран от Olly. А вот Olly лучше скачайте и посмотрите сами! Бай.

    (c) Robo
     
    2 пользователям это понравилось.
  4. Ассембли. Урок IV - Переменные и возвращаемые значения функций

    Ассембли. Урок IV - Переменные и возвращаемые значения функций

    Приветствую... Сегодняшний урок посвящённ переменным и значениям, которые возвращают функции API. Для более подробного понимания материала

    воспользуемся всё той-же функцией MessageBox. Вы можете спросить: что может возвращать простое окно сообщения? А возвращает она одно из следующих

    значений:

    IDABORT ; нажата кнопка ABORT
    IDCANCEL ; нажата кнопка CANCEL
    IDIGNORE ; нажата кнопка IGNORE
    IDNO ; нажата кнопка NO
    IDOK ; нажата OK
    IDRETRY ; нажата RETRY
    IDYES ; нажата кнопка YES

    Более подробную информацию по функциям API можно найти на MSDN (http://msdn2.microsoft.com/ru-ru/default.aspx), или в любом справочнике который

    поставляеться с продуктами от Borland. Посмотрим на следующий код:

    Код:
    	include 'D:\FASM\include\win32ax.inc'
    
    	.code
    
    	start:
    
            	invoke MessageBox,0,'привет!','заголовок',MB_OK   ; вызываем окошко
            	invoke ExitProcess,0    			  ; завершаем процесс
              
    	.end start
    
    Посмотрите стиль окошка - MB_OK, соответственно окошко выскочит с одной кнопкой OK. И если мы нажмём OK то функция возвратит IDOK. Но что если нам

    нужно например использовать две кнопки, например OK & CANCEL. Для этого есть специальный стиль окна - MB_OKCANCEL. Вообще они конечно описаны в MSDN,

    так что я не буду их приводить в этом тексте. Пример:

    Код:
    	include 'D:\FASM\include\win32ax.inc'
    
    	.code
    
    	start:
    
            	invoke MessageBox,0,'привет!','заголовок',MB_OKCANCEL   ; вызываем окошко
            	invoke ExitProcess,0    			  	; завершаем процесс
              
    	.end start
    
    Тогда, соответственно при выполнении этого кода, если мы нажали на OK, функция возвратит IDOK, если CANCEL - то получим IDCANCEL. Чтобы узнать что

    возвращает та или иная функция - обратитесь к MSDN (для этого знание технического английского вам поможет). Кстати функции возвращают значения через

    регистр EAX почти всегда. Так что, чтобы проверить возвращаемое значение - нужно проверить именно регистр EAX. Давайте сделаем проверку, при которой

    если мы нажимаем например на OK выскакивает окошко и говорит нам что мы нажали именно эту кнопку, если CANCEL - то соответственно сообщение будет

    другим:

    Код:
    	include 'D:\FASM\include\win32ax.inc'
    
    	.code
    
    	start:
    
                invoke MessageBox,0,'привет!','заголовок',MB_OKCANCEL      ; вызываем окошко
                cmp eax,IDOK                                               ; проверяем что нажали ok
                jz OK_PRESSED                                              ; если да - прыгаем на соответствующее сообщение
                invoke MessageBox,0,'вы нажали CANCEL','заголовок',MB_OK   ; если нет - то не прыгаем и выводим что нажали CANCEL
                jmp EXIT                                                   ; прыгаем на выход чтобы избежать появления второго окна
    
    	OK_PRESSED:
    
                invoke MessageBox,0,'вы нажали OK','заголовок',MB_OK       ; выводим сообщение про OK
    	EXIT:
    
                invoke ExitProcess,0                                       ; завершаем процесс
              
    	.end start
    
    Надеюсь из комментариев всё ясно, но на всякий случай поясню, что после того как мы вивели окно с приветствием, мы проверяем с помощью оператора CMP,

    значение регистра EAX и если там IDOK то прыгаем на сообщение и говорим что нажали OK, иначе выводим сообщение что нажали CANCEL и прыгаем на метку

    EXIT дабы избежать появления второго окна, ведь код продолжит выполняться и наткнёться на строку invoke MessageBox,0,'вы нажали OK','заголовок',MB_OK

    . То есть инструкцией jmp (безусловный переход) мы перепрыгиваем эту запись и выходим из программы.

    Теперь займёмся переменными:

    Переменные должны быть обьявлены в секции данных - .data . Сначала мы пишем имя переменной потом через пробел - её размер, и только потом через пробел

    её значение. Пример:

    Код:
    	include 'D:\FASM\include\win32ax.inc'
    
    	.data
    
    	perem1 dd 0
    
    	.code
    
    	start:
    
                	invoke ExitProcess,0
              
    	.end start 
    
    В этом примере мы обьявили переменную perem1 размером в 4 байта (dd - define dword (двойное слово - 4 байта)) и присвоили ей значение 0 (нуль). Теперь

    в неё можно писать данные, но не более 4 байт, так как мы задали размер именно в 4 байта. Можно считывать значение переменной итд. Кстати, для того

    чтобы считать значение переменной, её нужно обрамить скобками вот так:

    Код:
    	include 'D:\FASM\include\win32ax.inc'
    
    	.data
    
    	perem1 dd 0
    
    	.code
    
    	start:
    		
    		mov eax,[perem1]
                	invoke ExitProcess,0
              
    	.end start
    
    Но чтобы считать её адрес в памяти - обрамление скобками не требуеться. Пример:

    Код:
    	include 'D:\FASM\include\win32ax.inc'
    
    	.data
    
    	perem1 dd 0
    
    	.code
    
    	start:
    		
    		mov eax,perem1
                	invoke ExitProcess,0
              
    	.end start
    
    Давайте теперь примерим всё это на практике. Напимеш программу для вывода текста в окно при помощи переменных. Для этого рассмотрим параметры самой

    функции, которые кстати вы можете и сами посмотреть в MSDN, но у меня мало трафика и я приведу кусок из справки от Borland:

    int MessageBox(

    HWND hWnd, // handle of owner window
    LPCTSTR lpText, // address of text in message box
    LPCTSTR lpCaption, // address of title of message box
    UINT uType // style of message box
    );

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

    Сделаем это:

    Код:
            include 'D:\FASM\include\win32ax.inc'
    
            .data
    
            text db "наш текст",00h
            zagolovok db "заголовок",00h
    
            .code
    
            start:
                    
                    invoke MessageBox,0,text,zagolovok,0
                    invoke ExitProcess,0
              
            .end start
    
    Обратите внимание как мы обьявляем строки - как массив байтов, которые заканчиваються нулевым байтом. Кстати db - это обьявить байт. Заметьте также,

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

    (с) Robo
     
    1 человеку нравится это.
  5. Robo,
    о, вот этот урок хороший очень, я не знал что в асме можно переменные использовать)) +1
     
  6. Хочу еще! ;)
     
  7. ДА! Robo plzzzz пиши ещё очень нравятся твой уроки , столько всего , вот только стал изучать этот язык , ну и до этого не изучал ни одного.Щас разбираюсь и пытаюсь запомнить , что к чему , но радует что можно проверить что написал на практике )))) Robo +999.
     
  8. Между строками должна быть кортинка но линк битый.

    Есле не трудно перезалей картинке, и обнови линки в постах, тк многим без кортинок будет явно не понятно.
     
  9. Мдее, вот с картнками хреново. Впринципе от олли не долго сфоткать но с переходами - напряг. Чё нить придумаю

    Добавлено через 21 минуту
    Всё поправил теперь не пропадут
     
  10. Ошибка:
    Третий, после четвёртый. (Первый урок.)
    Мелоч, но при чтении глаза режет.
    Тем не менее пропали. Домен гика похоже анреган. \=
     
  11. xazlon,
    Поправил. Спасиба. А вот про geekgames? Хмм... Вроде на год регал ) Разберёмся

    Добавлено через 1 минуту
    Проблемы с хостингом )