> For the complete documentation index, see [llms.txt](https://yutewiyof.gitbook.io/intro-rev-ida-pro/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://yutewiyof.gitbook.io/intro-rev-ida-pro/chast-06.md).

# Часть 6

Давайте продолжим с арифметическими и логическими инструкциями.

**ADD A, B**

Инструкция складывает значение **B** и **A**, и помещает результат в **A**.

**A** может быть регистром или содержимым ячейки памяти, **B** может быть регистром, константой или содержимым ячейки памяти (**A** и **B** не должны быть в памяти в одно и то же время, в одной и той же инструкции)

Рассмотрим несколько примеров инструкции **ADD** ища текст **ADD** через **VEVIEWER**.

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2F-LjpMQPtDk4rae7nZwjQ%2F-Ljp8u9CLmYG5O5zVEp3%2F06-01.png?generation=1563189693591683\&alt=media)

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

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2F-LjttkJvbq8Uocl4jWiJ%2F-Ljtu1g8N5Ftuj27Qag6%2F02.png?generation=1563265880677839\&alt=media)

В этом примере, если **ECX** равно **10000**, то константа **4** складывается с ним и результат **10004** сохраняется в тот же **ECX**.

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2F-Ljp8rKyZvtadezPe2Vo%2F-Ljp8zpr-VX8KzOdt_7L%2F06-03.png?generation=1563186185025071\&alt=media)

В этом случае, инструкция добавит **0xFFFFFFFF** к значению **ECX**, которое получено на предыдущем шаге, т.е. содержимое адреса будет указывать сейчас на **ECX + 30**, если этот адрес имеет разрешение на запись, инструкция сложит значения и будет сохранять результат там.

Если содержимое **ECX**, для примера, равно **0x10000**, то по адресу **0x10030** содержимое этого адреса равно значению **1** и когда мы прибавляем к этому значению **0xFFFFFFFF**, что то же самое, что и **-1**, следовательно, результат был бы равен нулю и будет сохраняться по адресу **0x10030**.

В нашем **CRACKME.EXE** есть несколько примеров суммы двух регистров.

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2F-LjpMQPtDk4rae7nZwjQ%2F-Ljp8za1ihytn-Nnu0EP%2F06-04.png?generation=1563189699173098\&alt=media)

В этом случае, оба регистра будут сложены и сохранены в **EDI**.

Конечно, мы можем также складывать **16-**&#x431;итные и **8-**&#x431;итные регистры.

> ADD AL, 8
>
> ADD AX, 8
>
> ADD BX, AX
>
> ADD BYTE PTR DS: \[EAX], 7

Инструкция будет складывать байт содержимого на которое указывает **EAX**, и значение **7**, и будет сохранять результат в то же самое место.

И все возможные комбинации сумм между регистрами, содержимым ячеек памяти и константами, как мы видели все комбинации действительны, если только **EAX** не является константой и содержимым адреса памяти в одно и то же время в той же инструкции.

**SUB A, B**

Эта инструкция действует так же как и **ADD** за исключением того, что вместо операции сложения в данном случае вычитается целое число и сохранит результат в **A**, возможные комбинации те же самые.

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2F-LjttkJvbq8Uocl4jWiJ%2F-Ljtu1hFuVorTb9Fb4ha%2F05.png?generation=1563265877770050\&alt=media)

**INC A и DEC A**

Инструкция увеличивает или уменьшает регистр, или содержимое ячейки памяти на **1**, на самом деле это частный случай сложения и вычитания.

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2F-LjpMQPtDk4rae7nZwjQ%2F-Ljp8za5-f0yWW8KvWpD%2F06-06.png?generation=1563189693498485\&alt=media)

Оба используются для примера, чтобы увеличить или уменьшить счётчик на **1**.

**IMUL**

Это инструкция умножения со знаком и существует две её формы.

> IMUL A, B
>
> IMUL A, B, C

Первая инструкция выполняет целочисленное умножение **A** на **B**, и результат сохраняется в **A**, а вторая инструкция выполняет умножение **B** на **C**, и результат сохраняется в **A**.

В обоих случаях **A** может быть только регистром, **B** может быть регистром или содержимым ячейки памяти и **C** может быть только константой.

> IMUL EAX, \[ECX]
>
> IMUL ESI, EDI, 25

Давайте рассмотрим пример в **VEVIEWER**

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2F-LjpMQPtDk4rae7nZwjQ%2F-Ljp8u9VfWYSw1Z6FHZz%2F06-07.png?generation=1563189693687757\&alt=media)

Мы видим, что есть только примеры для первой инструкции, в обоих случаях будет производиться целочисленное умножение обоих членов и будет сохраняться результат в первый член - **ECX**.

Для второго случая примеров нет.

**IMUL EAX, EDI, 25**

Здесь инструкция умножает **EDI** на **25** и сохраняет результат в **EAX**, это очень легко.

**IDIV A**

В этом случае **A** определяет только **ДЕЛИТЕЛЬ** операции, делимое же как и частное не определяются, потому что они всегда используют одинаковые регистры.

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2F-LjpMQPtDk4rae7nZwjQ%2F-Ljp8u9X-nsCShpCdZDe%2F06-08.png?generation=1563189699416749\&alt=media)

Эта операция создаёт большое **64**-битное число, старшая часть которого находится в **EDX**, а младшая часть в **EAX**. Инструкция делит значение на **A** и сохраняет результат в **EAX**, а остаток значение в **EDX**.

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2F-LjttkJvbq8Uocl4jWiJ%2F-Ljtu1iIWLjN-DJ7bSH_%2F09.png?generation=1563265877047207\&alt=media)

Если **EAX** для примера равно **5**, **EDX** равно нулю и **ECX** равно **2** инструкция выполнит целочисленное деление, результат деления **5** на **2** будет равен **2** и он будет сохранён в **EAX**, а остаток сохранён в **EDX**.

То же самое произойдёт, если **A** - это содержимое ячейки памяти, **EDX:EAX** будет разделено на это значение и результат сохранится в **EAX**, а остаток в **EDX**.

## **ЛОГИЧЕСКИЕ ОПЕРАЦИИ**

**AND**, **OR** или **XOR**

**AND A, B**

Инструкция выполняет логическую операцию **И** между двумя значениями и будет сохранять результат в **A**, то же самое происходит с инструкциями **ИЛИ** или **XOR**, каждая инструкция имеет свою таблицу истинности, которая применяется к каждому члену и результат будет сохранён в **A**.

**A** и **B** могут быть регистрами или содержимым ячеек памяти, но запрещено, чтобы оба были содержимым ячейки памяти в одной и той же инструкции.

Самые используемые случаи - это применение **XOR** к одному и тому же регистру, чтобы легко и быстро изменить его в ноль.

**XOR EAX, EAX** для примера при любом значение **EAX** поместит в результате ноль, так как таблица истинности для **XOR** такая.

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2F-LjttkJvbq8Uocl4jWiJ%2F-Ljtu1ia9WQ7KsLOOMFi%2F10.png?generation=1563265877314525\&alt=media)

В этом случае результат - это последняя колонка и мы видим, что если **XOR**им число против себя , это может случиться только, когда в двочином виде оба биты равны нулю или оба бита равны единице, так как это то же самое число, **A** и **B** равны и побитовый результат всегда даёт ноль в обоих случаях.

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2F-LjttkJvbq8Uocl4jWiJ%2F-Ljtu1ivPDxS5QOvHZxd%2F11.png?generation=1563265880231818\&alt=media)

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2F-LjttkJvbq8Uocl4jWiJ%2F-Ljtu1j8Km4K1PfB2b0y%2F12.png?generation=1563265877286334\&alt=media)

Записывая значения как бинарные данные в **PYTHON** строке и используя символ **^**, который является операцией **XOR** в **PYTHON**, я вижу, что применяя операцию **XOR** два одинаковых числа всегда дают **0**.

Конечно, можно использовать десятичные и шестнадцатеричные значения, я просто использовал двоичный режим чтобы увидеть как бит влияет на бит.

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2F-LjpMQPtDk4rae7nZwjQ%2F-Ljp8u9gyAR4mq3a2twS%2F06-13.png?generation=1563189699390890\&alt=media)

Другое простое использование для примера.

**AND EAX, 0F**

**0F** это **1111** в двоичной системе счисления.

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2F-LjpMQPtDk4rae7nZwjQ%2F-Ljp8u9iYvzdw7qkbCE2%2F06-14.png?generation=1563189693509689\&alt=media)

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2F-LjttkJvbq8Uocl4jWiJ%2F-Ljtu1jpu8-Uv1Fg2WEq%2F15.png?generation=1563265877148520\&alt=media)

Мы видим, что второй член равен **1**, результат не изменится, он останется равным как был первоначально, в то время как все другие биты станут равны нулю.

Таким образом, я легко поместил нули во все биты числа и оставил последние **4** бита нетронутыми.

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2F-LjttkJvbq8Uocl4jWiJ%2F-Ljtu1kU249H-fgf0chw%2F16.png?generation=1563265877072457\&alt=media)

Там мы видим, что **AND** в **PYTHON** записывается символом **&** и результатом является **0B0111**, а это последние четыре первоначальные биты.

В случае **OR** в **PYTHON** он записывается как вертикальная черта.

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2F-Ljp8rKyZvtadezPe2Vo%2F-Ljp8zqV1DU6MIvy3EcE%2F06-17%20\(2\).png?generation=1563186181861828\&alt=media)

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

**NOT A**

Инструкция инвертирует все биты **A** и сохраняется затем в **A**.

Инструкция **NOT** не существует в **PYTHON**, но это очень просто, если Вы имеете число **0101** и Вы применяете к нему операцию **NOT**.

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2F-Ljp8rKyZvtadezPe2Vo%2F-Ljp8zqXNukhGA5h3jE3%2F06-18%20\(1\).png?generation=1563186184701982\&alt=media)

Результатом будет инверсия каждого бита.

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2F-LjttkJvbq8Uocl4jWiJ%2F-Ljtu1l2EHfydGhrgDC2%2F19.png?generation=1563265877713068\&alt=media)

Мы видим, что все нули изменились в один и наоборот.

**NEG A**

**NEG A** превращает **A** в **-A**.

Это не то же, что операция **\~** в **PYTHON**, потому что тут ещё вычитается единица.

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2F-LjttkJvbq8Uocl4jWiJ%2F-Ljtu1lBo3epcQWYV55b%2F20.png?generation=1563265877238367\&alt=media)

Чтобы получить **NEG** в **Python** мы должны добавить к результату **1**.

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2F-Ljp8rKyZvtadezPe2Vo%2F-Ljp8zqc1PY1B3rkC6DW%2F06-21%20\(2\).png?generation=1563186181185783\&alt=media)

> SHL, SHR
>
> SHL A, B
>
> SHR A, B

**A** может быть регистром или ячейкой в памяти, а **B** константой или **8-бит**. регистром.

Эти инструкции сдвигают байты влево(**SHL**) и вправо (**SHR**), байты которые исчезают с одной стороны, заменяются нулями с другой стороны, давайте рассмотрим пример.

Предположим, что у нас есть **-1**, для примера.

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2F-LjttkJvbq8Uocl4jWiJ%2F-Ljtu1lUV9aMgmiSf8PW%2F22.png?generation=1563265877148143\&alt=media)

И если я сделал **SHL 2**, я получу.

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2F-Ljp8rKyZvtadezPe2Vo%2F-Ljp8zqgthrHSKhLVQaw%2F06-23%20\(2\).png?generation=1563186185154783\&alt=media)

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

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2F-Ljp8rKyZvtadezPe2Vo%2F-Ljp8zqi2a-Acup65W8A%2F06-24%20\(2\).png?generation=1563186185019174\&alt=media)

То же самое произойдёт, если мы используем **SHR**, биты сдвинутся к правой стороне. Те биты которые исчезнут с правой стороны, будут заменены на **0** с левой стороны.

Существуют также инструкции **ROL** и **ROR**, которые похожи, они вращают определенное количество бит, но в этом случае те биты, которые исчезают с одной стороны, возвращаются с другой стороны с теми же значениями, это пример чистого вращения битов, так как не меняется ни один бит, они просто крутятся.

![](https://333516620-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Ljp8Kl9OQ2AqdU_D0G8%2F-Ljp8rKyZvtadezPe2Vo%2F-Ljp8zqkCuxA1Ra_m929%2F06-25.png?generation=1563186184499633\&alt=media)

До встрече в **7**-й главе.

Автор оригинального текста — Рикардо Нарваха.

Перевод и адаптация на английский язык — IvinsonCLS.

Перевод и адаптация на русский язык — Яша Яшечкин.

[**Источник: ricardonarvaja.info**](http://ricardonarvaja.info/WEB/IDA%20DESDE%20CERO/CURSO%20DE%20IDA%20TUTES/6-INTRODUCCION%20AL%20REVERSING%20CON%20IDA%20PRO%20DESDE%20CERO.docx)
