Ну вот я снова развернул клаву и строчу текст .. итак, что же
ждёт юного хакера в этот раз.. Написав предыдущую статью я понял,
что одного простого приложения, для демонстрации кульных
возможностей
при программировании на Ассемблере под Винду, недостаточно, что я
и решил исправить в новой статье ..
При рассмотрении команд я не затрагивал и не буду таких вещей как
допустимые источники данных, состояние флагов после выполнения
операций, а так же рассмотрение большей части инструкций. Эти моменты
достаточно важны при программировании вообще, но для целей минимизации
объёма информации (читай упрощения) статьи я их не учитывал ..
так что, если есть всё-таки желание программировать в этом направлении,
рекомендую подкрепить его хорошей книжкой по Ассемблеру ..
В: для чего тогда я вообще написал эту статью?
О: в реальной жизни простого программера, типа меня (посредственный 🙂 ..
и к тому же не программер ;)), встречается лишь малая часть из этой
информации, те. если не писать на Ассемблере кодеки VQF и драйверы
GeForce большинство возможностей Ассемблера просто не используются ..
В: почему статья про написание прог под Винду?
О: ..ну .. что есть, о том и пишу 🙁 .. и к тому же реализовывать интерфейс
из консоли .. хмм, извольте ..
Ну что ж, приступим .. для начала дополню набор ОПКОДОВ, рассмотренный в
предыдущей статье:
Операции с адресами
LEA (Load Effective Address) - Загрузка эффективного адреса
lea приемник,источник
Используется для получения эффективного адреса (смещения) источника.
Пример:
.data
massiv db 5 dup (0)
.code
...
mov di,4
lea bx,massiv[di]
;или
lea bx,massiv[4]
;или
lea bx,massiv+4
Битовые операции
BT (Bit Test) - Проверка битов
bt источник,номер_бита
Извлекает значение заданного бита в флаг cf.
Пример:
mov ebx,01001100h
bt ebx,3 ;проверка состояния бита №3 и установка cf= в 1
;биты считаются начиная с 0 справа налево
jc m1 ;перейти на m1, если проверяемый бит равен 1
BTC (Bit Test and Complement) Проверка бита с его инверсией
BTR (Bit Test and Reset) - Проверка бита с его сбросом в 0
BTS (Bit Test and Set) - Проверка бита с его установкой в 1
(3 последние команды по формату аналогичны BT)
Подробное пояснение работы (по итогам предыдущей статьи):
RCL (Rotate operand through Carry flag Left)
Циклический сдвиг операнда влево через флаг переноса CF
rcl операнд,количество_сдвигов
Как это всё происходит:
сдвиг всех битов операнда влево на один разряд, при этом старший бит операнда становится значением флага переноса cf; одновременно старое значение флага переноса cf вдвигается в операнд справа и становится значением младшего бита операнда; указанные выше два действия повторяются количество раз, равное значению второго операнда команды rcl (до 31 из-за ограничений проца).
RCR (Rotate operand through Carry flag Right)
Циклический сдвиг операнда вправо через флаг переноса СF
rcr операнд,количество_сдвигов
аналогична предыдущей операции, но противоположное направление сдвига.
Команды без параметров:
STC (Set Carry Flag) - Установка флага переноса в 1
CLC (CLear Carry flag) - Сброс флага переноса в 0
CMC (CoMplement Carry flag) - Инвертирование флага переноса
CLD (CLear Direction flag) - Сброс флага направления
(DF - флаг направления используется в цепочечных
командах для задания
направления обработки: DF=0 - от начала строки к концу, DF=1 - наоборот)
STD (SeT Direction Flag) - Установка флага направления в 1
Арифметические операции
IDIV (Integer DIVide) - Деление целочисленное со знаком
idiv делитель (делимое в ax)
Пример:
mov ax,1045 ;делимое
mov bx,587 ;делитель
cwd ;расширение делимого dx:ax (знаковым битом ax заполняем dx)
idiv bx ;частное в ax, остаток в dx
IMUL (Integer MULtiply) - Умножение целочисленное со знаком
imul множитель_1
imul множ_1,множ_2
imul рез-т,множ_1,множ_2
Пример:
mov bx,186
imul eax,bx,8
;если результату не хватило размерности операнда1,
;то перейдем на m1, где скорректируем ситуацию:
jc m1
NEG (NEGate operand) - Изменить знак операнда
mov al,2
neg al ;al=0feh — число -2 в дополнительном коде
MOVSX (MOVe and Sign eXtension) - Пересылка со знаковым расширением
Пример:
mov al,f1h
movsx bx,al ;bx=fff1h , те. знаком al заполняем bh
(в дальнейшем я не рассматриваю двоичную и двоично-десятичную арифметику,
т/к. это требует дополнительного объяснения, к тому
же достаточно немалого,
про её принципы .. 🙁
Операции со стеком
ENTER (setup parameter block for ENTERing procedure) - Устанавливает
границы в стеке для локальных переменных процедуры.
enter размер_памяти_для_переменных(word), уровень_вложенности(byte)
Команда enter была введена в систему команд микропроцессора для
поддержки структурированных языков высокого уровня типа Pascal/С.
В этих языках программа разбивается на блоки. В блоках можно описать
свои собственные (локальные) переменные, которые не могут быть
использованы вне этого блока.
Пример:
.386
proc1 proc
;зарезервировать в стеке место для локальных переменных
;proc1 в количестве 16 байт
;уровень вложенности 0
enter 16,0
mov byte ptr [ebp-1], al
;доступ к локальным переменным
осуществляем через ebp
;замечу, что именно из-за этого ebp не рекомендуют юзать
;при различных вычислениях ..
...
leave
ret
proc1 endp
LEAVE (LEAVE from procedure) - Выход из процедуры, использующей ENTER
Удаляет из стека область локальных переменных,
выделенную командой enter.
PUSHAD (PUSH All general Double word registers onto stack)
Размещение в стеке регистров общего назначения в следующей
последовательности: eax, ecx, edx, ebx, esp, ebp, esi, edi.
POPAD (POP All general Double word registers from the stack)
Извлечение всех регистров общего назначения из стека (порядок
обратный предыдущей команде edi, esi ..).
PUSHFD (PUSH eFlags Double word register onto stack)
Размещение в стеке содержимого регистра флагов eflags.
POPFD (POP eFlags Double word register from the stack)
Извлечение расширенного регистра флагов из стека
Управление циклами:
LOOP (LOOP control by register ecx) управление циклом по ecx
loop метка
Пример:
mov ecx,10 ;в есх записываем число повторов
cycl:
;делаем какие-то операции
loop cycl
LOOPE/LOOPZ (LOOP control by register ecx not equal 0 and ZF=1)
LOOPNE/LOOPNZ (LOOP control by register ecx not equal 0 and ZF=0)
Управление циклом по ecx c учетом значения флага ZF
REP/REPE/REPZ/REPNE/REPNZ (REPeat string operation)
rep опкод
аналогична соответствующему (JMP,JE итп.) условному переходу,
зацикливающему следующую операцию, причём в регистре ecx находится
количество повторов для операции.
Пример:
repe scasb
Цепочечные операции:
CMPS/CMPSB/CMPSW/CMPSD (CoMPare String Byte/Word/Double word operands)
Сравнение строк байтов/слов/двойных слов
cmps приемник,источник
Пример:
.data
obl1 db 'Строка для сравнения'
obl2 db 'Строка для сравнения'
.code...
cld ;просмотр цепочки в направлении возрастания адресов
mov ecx,20 ;длина цепочки(строки)
lea esi,obl1 ;адрес первой строки в esi
lea edi,obl2 ;адрес второй строки в edi
repe cmpsb ;сравнивать, пока равны
jnz m1 ;если не конец цепочки (встретились разные элементы)
... ;действия, если цепочки совпали
...
m1:
... ;действия, если цепочки не совпали
SCAS/SCASB/SCASW/SCASD Сканирование строки байтов/слов/двойных слов
scas приемник (по умолчанию - al/ax/eax)
Ищет значение в цепочке элементов, находящихся в памяти.
(направление зависит от флага DF)
lea edi,str
mov ecx,len_str ;длину строки — в ecx
mov al,' ' ;элемент для поиска в еах
mov bx,0 ;счетчик для подсчета пробелов в строке
cld ;ищем по возрастанию адреса (DF=0)
cycl:
repe scasb
jcxz exit ;переход на exit, если цепочка просмотрена полностью
inc bx
jmp cycl
exit: ...
LODS/LODSB/LODSW/LODSD (LOad String Byte/Word/Double word operands)
Сохраняет элемент цепочки в al/ax/eax.
cld
lea esi,str
lodsb ;загрузить первый байт из str в al
STOS/STOSB/STOSW/STOSD (Store String Byte/Word/Double word operands)
Записывает al/ax/eax в данную цепочку (обратная операция - LODS/..).
;заполнить некоторую область памяти пробелами
str db 'Какая-то строка'
len_str=$-str ;длина строки
.code
cld
mov al,' '
lea edi,str
mov ecx,len_str
rep stosb ;заполняем пробелами строку str
;пример совместной работы stosb и lodsb:
;копировать одну строку в другую до первого пробела
str1 db 'Какая-то строка'
len_str1=$-str
str2 db len_str1 dup (' ')
.code
cld
mov ecx,len_str1
lea esi,str1
lea edi,str2
m1: lodsb
cmp al,' '
je exit ;выход, если пробел
stosb
loop m1
exit:
MOVS/MOVSB/MOVSW/MOVSD (MOVe String Byte/Word/Double word)
Выполняет пересылку строк байтов/слов/двойных слов
movs приемник,источник
Пример:
str1 db 'str1 копируется в str2'
len_str1=$-str1 ;$ -означает текущую позицию
str2 db len_str1 dup (' ')
...
mov ecx,len_str1
lea esi,str1
lea edi,str2
cld
rep movsb
Другое:
SETcc (byte SET on condition) - Установка байта по условию
setcc операнд(1 байт)
похожа на условные переходы, только вместо перехода устанавливается
в соответствующее значение операнд команды.
Пример:
setnz al ;установить al=1 если ZF=0
CMPXCHG (CoMPare and eXCHanGe) - Сравнение и обмен
cmpxchg приемник,источник
Выполняет сравнение и обмен значений между источником и приемником.
XLAT/XLATB (transLATe Byte from table) - Преобразование байта
xlat адрес_таблицы_байтов xlatb
Назначение: подмена байта в регистре al байтом из таблицы
table db 'abcdef..'
int db 0 ;значение индекса
...
mov al,3
lea ebx,table
xlat ;(al)='c'
В винде из-за ограничений наших win32-прог (Ring-3 app) этими 2мя
командами пользоваться пока не придётся ..
IN (INput operand from port) - Ввод операнда из порта
in аккумулятор,ном_порта
Пример:
push ax ;сохраним его на время
in al,61h ;читаем порт 61h
or al,80h ;старший бит байта из порта 61h в 1
out 61h,al ;подтверждаем факт приема скан-кода
pop ax
out 61h,al ;восстановили байт в порту 61h
OUT (OUT operand to port) - Вывод операнда в порт
out ном_порта,аккумулятор
Пример:
out 64h,al
Данный набор команд не претендует на полный .. но пока хватит, а теперь
перейдём к очередной проге - серверу простого
(но это ещё не значит малофункционального) трояна...