Ассемлерные инструкции

NOP (NO OPERATION)

Ничего не делать. В OllyDbg можно занопить инструкцию.


При выполнении инструкции NOP кроме регистра EIP ничего не меняется.

Если в окне дампа нажать Ctrl+G и перейти на адрес инструкции, то мы увидим два красных байта, которые мы изменили.


Изменения можно отменить, если выделить их в окне дампа или кода и выбрать пункт контекстного меню Undo Selection.

Наложенные изменения можно смотреть в окне патчей (/).

Инструкции стека: PUSH, POP


Инструкция PUSH помещает значение на вершину стека, а то что было наверху оказывается под этим значением.

Примечательно, что если адреса инструкций совпадали у меня и в туториале, то адреса в стеке как говорит автор могут не совпадать. Но у меня совпадают. Так как стек каждый раз может располагаться по разному адресу.

После PUSH-а меняется регистр ESP, который указывает на новую вершину стека.



PUSH EAX ; поместить в стек значение регистра
PUSH [401008] ; поместить в стек значение в памяти
PUSH DWORD PTR DS:[401008] ; эквивалентно предыдущей инструкции
PUSH 401008 ; поместить в стек число

При помещении в стек значения из памяти, сходите на панель дампа и с помощью GOTO EXPRESSION 401008 посмотрите, что там находится. Те четыре байта которые там находятся будут помещены в стек. Если иное не задано специально, то OllyDbg считает, что надо читать 4 байта из памяти. Но они будут помещены в обратном порядке. Например, если у нас по адресу 401008 находятся:
CA 20 40 00
то в стек они запишутся как:
00 40 20 CA
Это потому что при чтении или записи содержимого из/в память байты всегда переворачиваются.


Инструкция POP выполняет обратное действие по отношению к PUSH. Пример:
POP EAX

Инструкция PUSHAD эквивалентна PUSH EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI. Обратная инструкция POPAD. Существуют также 16-битные эквиваленты PUSHA и POPA:
PUSH AX, CX, DX, BX, SP, BP, SI, DI
POP DI, SI, BP, SP, BX, DX, CX, AX

Инструкции для перемещения данных

Первым идет приемник куда будет помещаться значение, а вторым источник откуда оно будет браться.

MOV EAX, EBX
MOV AL, CL
MOV EAX, DWORD PTR DS:[405000]
MOV DWORD PTR DS:[4020CA], EAX

DWORD означает, что нужно переместить 4 байта. Эта инструкция может вызвать ошибку, если заданная ячейка в памяти не существует. Проверяйте через окно дампа и меню GOTO EXPRESSION 405000.

Помните, что содержимое в памяти хранится в перевернутом виде. Например, если содержимое ячейки памяти 00 10 00 00, то в EAX попадет 00 00 10 00.

В статусной строке OllyDbg может появится сообщение Access violation when writing to [00400500], это значит, что вы хотите записать в секцию в которую писать запрещено. Права на работу с секциями можно менять.

WORD используется для помещения двух байтов, а BYTE для помещения одного байта.

MOV AX, WORD PTR DS:[405008]
MOV AL, BYTE PTR DS:[405008]

Инструкция MOVSX (Move with Sign-Extension) копирует содержимое второго операнда (регистр, адрес в памяти) в первый, который должен быть в 2 раза больше, чем второй. Заполняя остальные биты слева значением самого значимого бита второго операнда. 

Мы используем HEX-числа, но если вы посмотрите их бинарные эквиваленты, то отрицательных чисел первый бит будет 1, а у положительных 0. Вспомните про деление доступного диапазона на отрицательные и положительные числа.

; EAX = 0000 0000
; BX = F000 // отрицательное 16-битное число
MOVSX EAX, BX
; EAX = FFFF F000

; EAX = 0000 0000
; BX = 1234 // положительное 16-битное число
MOVSX EAX, BX
; EAX = 0000 1234

Концепция положительных и отрицательных чисел в 16-битах работает также как и для 32-битных, только в интервале от 0000 до FFFF. Числа от 0000 до 7FFF являются положительными, а всё, что выше до FFFF - отрицательными.

; EAX = 0000 0000
; BX = 7FFF // положительное 16-битное число
MOVSX EAX, BX
; EAX = 0000 7FFF

; EAX = 0000 0000
; BX = 8000 // отрицательное 16-битное число
MOVSX EAX, BX
; EAX = FFFF 8000

Инструкция MOVZX (Move with Zero-Extend) похожа на предыдущую, только свободно место всегда заполняется нулями и не зависит от того является ли второй операнд положительным или нет.

Инструкция LEA (Load Effective Address) похожа на инструкцию MOV, но первый операнд - это регистр общего назначения, а второй - адрес ячейки памяти. Это инструкция полезна, когда адрес зависит от предыдущих вычислений.

LEA EAX, DWORD PTR DS:[ECX+38]

В квадратных скобках задан адрес не напрямую, а вычисления в результате которых он получается. Можно подумать, что в EAX попадет содержимое по результирующему адресу, как это было бы в случае с MOV, однако в EAX попадет сам адрес.

Инструкция XCHG обменивает содержмое двух операндов:

XCHG EAX, ECX
XCHG DWORD PTR DS:[405000], EAX