reverseenengineering:ветвления

Различия

Показаны различия между двумя версиями страницы.

Ссылка на это сравнение

Предыдущая версия справа и слева Предыдущая версия
reverseenengineering:ветвления [2025/07/16 21:34] Lexreverseenengineering:ветвления [2025/07/16 21:39] (текущий) Lex
Строка 6: Строка 6:
 Ветвление (branching) — это переход исполнения программы на другую инструкцию, обычно по условию. Вот основные виды ветвления (на примере x86): Ветвление (branching) — это переход исполнения программы на другую инструкцию, обычно по условию. Вот основные виды ветвления (на примере x86):
  
-Безусловный переход: :: ''JMP label'' +  * **Безусловный переход**: :: ''JMP label'' 
-Условный переход по флагам: :: ''Jcc label'' (JE, JNE, JL, JG и др.) +  * **Условный переход по флагам**: :: ''Jcc label'' (JE, JNE, JL, JG и др.) 
-Переход с возвратом: :: ''CALL label'', ''RET'' +  * **Переход с возвратом**: :: ''CALL label'', ''RET'' 
-Циклические переходы: :: ''LOOP label'', ''LOOPE'', ''LOOPNE'' +  * **Циклические переходы**: :: ''LOOP label'', ''LOOPE'', ''LOOPNE'' 
-Косвенные переходы: :: ''JMP [reg]'' +  * **Косвенные переходы**: :: ''JMP [reg]'' 
-Табличные переходы: :: через адресацию перехода по таблице (jump table) +  * **Табличные переходы**: :: через адресацию перехода по таблице (jump table) 
-Прерывания и возврат из них: :: ''INT N'', ''IRET''+  * **Прерывания и возврат из них**: :: ''INT N'', ''IRET'' 
 Желающие подробности по архитектурам — читайте далее. Желающие подробности по архитектурам — читайте далее.
 +
 +
 +----
  
 ==== 2. x86 (Intel) ==== ==== 2. x86 (Intel) ====
Строка 21: Строка 25:
 После арифметической/логической операции процессор выставляет флаги в регистре EFLAGS: После арифметической/логической операции процессор выставляет флаги в регистре EFLAGS:
  
-^ Название | Описание | | ZF (Zero Flag) | Результат 0? (1 если да) | | SF (Sign Flag) | Знак результата (1=минус) | | CF (Carry Flag) | Перенос (важно при беззнаковых) | | OF (Overflow Flag) | Переполнение (важно при знаковых) | | PF (Parity Flag) | Четность (не часто используется) |+^ Название | Описание | 
 +| ZF (Zero Flag) | Результат 0? (1 если да) | 
 +| SF (Sign Flag) | Знак результата (1=минус) | 
 +| CF (Carry Flag) | Перенос (важно при беззнаковых) | 
 +| OF (Overflow Flag) | Переполнение (важно при знаковых) | 
 +| PF (Parity Flag) | Четность (не часто используется) |
  
 === 2.2. Основные команды ветвления === === 2.2. Основные команды ветвления ===
  
-^ Инструкция | Условие | Обозначение | | JE/JZ | ZF = 1 | Равно ("Jump if Equal") | | JNE/JNZ | ZF = 0 | Не равно | | JL | (SF ≠ OF) | Меньше (signed) | | JLE | (ZF=1 or SF ≠ OF) | Меньше или равно (signed) | | JG | (ZF=0 and SF=OF) | Больше (signed) | | JGE | (SF=OF) | Больше или равно (signed) | | JB | CF = 1 | Меньше (unsigned) | | JBE | CF=1 or ZF=1 | Меньше или равно (unsigned) | | JA | (CF=0 and ZF=0) | Больше (unsigned) | | JAE | CF = 0 | Больше или равно (unsigned) | | CALL, RET | | Вызов и возврат процедуры | | JMP [рег] | | Косвенный переход |+^ Инструкция | Условие | Обозначение | 
 +| JE/JZ | ZF = 1 | Равно ("Jump if Equal") | 
 +| JNE/JNZ | ZF = 0 | Не равно | 
 +| JL | (SF ≠ OF) | Меньше (signed) | 
 +| JLE | (ZF=1 or SF ≠ OF) | Меньше или равно (signed) | 
 +| JG | (ZF=0 and SF=OF) | Больше (signed) | 
 +| JGE | (SF=OF) | Больше или равно (signed) | 
 +| JB | CF = 1 | Меньше (unsigned) | 
 +| JBE | CF=1 or ZF=1 | Меньше или равно (unsigned) | 
 +| JA | (CF=0 and ZF=0) | Больше (unsigned) | 
 +| JAE | CF = 0 | Больше или равно (unsigned) | 
 +| CALL, RET |  | Вызов и возврат процедуры | 
 +| JMP [рег] |  | Косвенный переход |
  
 === 2.3. Примеры кода и пояснения === === 2.3. Примеры кода и пояснения ===
  
-==== Безусловный переход ==== <code> JMP somewhere </code>+==== Безусловный переход ==== 
 +<code> 
 +JMP somewhere 
 +</code>
  
 ==== Условный переход и работа флагов ==== ==== Условный переход и работа флагов ====
  
-<code> mov eax, -3 ; eax = FFFFFFFDh (32-битный -3) mov ebx, 1 ; ebx = 00000001h cmp eax, ebx ; вычитание: -3 - 1 = -4 (0xFFFFFFFCh) jg more_label ; если eax > ebx (signed)? jl less_label ; если eax < ebx (signed)? je equal_label ; если eax == ebx? +<code> 
-mov ecx, 123 jmp end+mov  eax, -3         ; eax = FFFFFFFDh (32-битный -3) 
 +mov  ebx, 1          ; ebx = 00000001h 
 +cmp  eax, ebx        ; вычитание: -3 - 1 = -4 (0xFFFFFFFCh) 
 +jg   more_label      ; если eax > ebx (signed)? 
 +jl   less_label      ; если eax < ebx (signed)? 
 +je   equal_label     ; если eax == ebx?
  
-more_label: mov ecx, jmp end+mov ecx, 123 
 +jmp end
  
-less_label: mov ecx, jmp end+more_label: 
 +mov ecx, 
 +jmp end
  
-equal_label: mov ecx, 3+less_label: 
 +mov ecx, 
 +jmp end
  
-end</code>+equal_label: 
 +mov ecx, 3
  
-Анализ флагов:+end: 
 +</code>
  
-После '''cmp eax, ebx''': +**Анализ флагов:**
-ZF = 0 (результат не ноль) +
-SF = 1 (отрицательное) +
-OF = 0 (переполнения нет) +
-CF = 1 (был аём" беззнаково) +
-'''jg'''требует ZF=0 и SF=OF (1 ≠ 0 -- не равно, перехода нет) +
-'''jl''': SF ≠ OF? (1 ≠ 0 — переход будет!) +
-==== Проверка на равенство ==== <code> mov eax, 7 mov ebx, 7 cmp eax, ebx je eq_label ; ZF=1, переход будет jne neq_label ; ZF=0, переход не будет </code>+
  
-==== Цикл ==== <code> mov cx5 loop_start: ; ... тело цикла loop loop_start </code>+  * После '''cmp eax, ebx''': 
 +    * ZF 0 (результат не ноль) 
 +    * SF 1 (отрицательное) 
 +    * OF 0 (переполнения нет) 
 +    * CF 1 (был "заём" беззнаково) 
 +  * '''jg''': требует ZF=0 и SF=OF (1 ≠ 0 -- не равноперехода нет) 
 +  * '''jl''': SF ≠ OF? (1 ≠ 0 — переход будет!)
  
-==== Вызов функции ==== <code> call my_function ; ... my_function: ; действия ret </code> 
  
-==== Косвенный переход ==== <code> jmp [ebx] ; ebx — адрес новой инструкции </code>+==== Проверка на равенство ==== 
 +<code> 
 +mov eax, 7 
 +mov ebx, 7 
 +cmp eax, ebx 
 +je  eq_label  ; ZF=1, переход будет 
 +jne neq_label ; ZF=0, переход не будет 
 +</code> 
 + 
 + 
 +==== Цикл ==== 
 +<code> 
 +mov cx, 5 
 +loop_start: 
 + ; ... тело цикла 
 +loop loop_start 
 +</code> 
 + 
 + 
 +==== Вызов функции ==== 
 +<code> 
 +call my_function 
 +; ... 
 +my_function: 
 + ; действия 
 +ret 
 +</code> 
 + 
 +==== Косвенный переход ==== 
 +<code> 
 +jmp [ebx]   ; ebx — адрес новой инструкции 
 +</code> 
 + 
 + 
 +----
  
 ==== 3. ARM ==== ==== 3. ARM ====
Строка 65: Строка 133:
 === 3.1. Флаги === === 3.1. Флаги ===
  
-^ Флаг | Назначение | | N (Negative) | Результат отрицательный? (MLSB=1) | | Z (Zero) | Результат 0? | | C (Carry) | Перенос/заём для беззнаковых | | V (Overflow) | Переполнение для знаковых |+^ Флаг | Назначение | 
 +| N (Negative) | Результат отрицательный? (MSB=1) | 
 +| Z (Zero) | Результат 0? | 
 +| C (Carry) | Перенос/заём для беззнаковых | 
 +| V (Overflow) | Переполнение для знаковых |
  
 Инструкции, которые изменяют флаги — обычно с S: '''ADDS''', '''SUBS''', '''CMP''', '''ANDS''' и др. Инструкции, которые изменяют флаги — обычно с S: '''ADDS''', '''SUBS''', '''CMP''', '''ANDS''' и др.
Строка 73: Строка 145:
 Любая инструкция ветвления (и почти любая другая) может иметь суффикс условия: Любая инструкция ветвления (и почти любая другая) может иметь суффикс условия:
  
-^ Суффикс | Условие | Описание | | EQ | Z=1 | Равно | | NE | Z=0 | Не равно | | LT | N ≠ V | Меньше (signed) | | GT | Z=0 и N=V | Больше (signed) | | GE | N=V | Больше или равно (signed) | | LE | Z=1 или N ≠ V | Меньше или равно (signed) | | CS/HS | C=1 | Беззнаково >= | | CC/LO | C=0 | Беззнаково < |+^ Суффикс | Условие | Описание | 
 +| EQ | Z=1 | Равно | 
 +| NE | Z=0 | Не равно | 
 +| LT | N ≠ V | Меньше (signed) | 
 +| GT | Z=0 и N=V | Больше (signed) | 
 +| GE | N=V | Больше или равно (signed) | 
 +| LE | Z=1 или N ≠ V | Меньше или равно (signed) | 
 +| CS/HS | C=1 | Беззнаково >= | 
 +| CC/LO | C=0 | Беззнаково < |
  
 === 3.3. Примеры кода и пояснения === === 3.3. Примеры кода и пояснения ===
  
-==== Пример: ==== <code> MOV R0, #5 MOV R1, #8 CMP R0, R1 ; R0 - R1 = -3 (Negative) BEQ label_eq ; Z=1 ? BNE label_ne ; Z=0 ? BLT label_lt ; N ≠ V ? </code>+==== Пример: ==== 
 +<code> 
 +MOV R0, #5 
 +MOV R1, #8 
 +CMP R0, R1      ; R0 - R1 = -3 (Negative) 
 +BEQ label_eq    ; Z=1 ? 
 +BNE label_ne    ; Z=0 ? 
 +BLT label_lt    ; N ≠ V ? 
 +</code>
  
-После CMP:+После CMP: 
 +  * N = 1 (отрицательное) 
 +  * Z = 0 (не ноль) 
 +  * V = 0 
 +  * C = 0
  
-N = 1 (отрицательное) +BEQ — не сработает (Z=0) 
-Z = 0 (не ноль) +* BNE — выполнится (Z=0) 
-V = 0 +* BLT — N ≠ V (1 ≠ 0) — выполнится
-C = 0 +
-BEQ — не сработает (Z=0)+
  
-BNE — выполнится (Z=0)+==== Вызовы процедур ==== 
 +<code> 
 +BL  myfunc     ; вызов с занесением адреса возврата в LR 
 +; ... 
 +myfunc: 
 + ; ... 
 + BX LR         ; возврат 
 +</code>
  
-BLT — N ≠ V (1 ≠ 0) — выполнится+==== Табличный переход ==== 
 +<code> 
 +CMP R0, #3 
 +BHI default 
 +LDR PC, [PC, R0, LSL #2]  ; PC ← (таблица адресов: case0, case1...)
  
-==== Вызовы процедур ==== <code> BL myfunc ; вызов с занесением адреса возврата в LR ; ... myfunc: ; ... BX LR ; возврат </code>+.word case0 
 +.word case1 
 +.word case2 
 +.word case3
  
-==== Табличный переход ==== <code> CMP R0, #3 BHI default LDR PC, [PC, R0, LSL #2] ; PC ← (таблица адресов: case0, case1...)+case0
 +... 
 +BX LR
  
-.word case0 .word case1 .word case2 .word case3+default: 
 +</code>
  
-case0: ; ... BX LR +----
- +
-default: </code>+
  
 ==== 4. MIPS ==== ==== 4. MIPS ====
Строка 107: Строка 212:
 Всё ветвление идёт по значению регистров. Всё ветвление идёт по значению регистров.
  
-^ Инструкция | Что выполняет | | beq  +^ Инструкция | Что выполняет | 
-+| beq $a, $b, label | Переход, если равны ($a = $b) | 
-+| bne $a, $b, label | Переход, если не равны | 
-a,b, label | Переход, если равны ( +| slt $r, $a, $   | $r = 1, если $a < $b (signed), иначе 0 | 
-+| sltu $r, $a, $  | $r = 1, если $a < $b (unsigned) | 
-+| jal, jr $ra       | Вызов/возврат процедуры | 
-a=b) | | bne  +
-+
-+
-a,b, label | Переход, если не равны | | slt  +
-+
-+
-r,a,  +
-b +
-∣ +
-b∣r = 1, если  +
-+
-+
-a<b (signed), иначе 0 | | sltu  +
-+
-+
-r,a,  +
-b +
-∣ +
-b∣r = 1, если  +
-+
-+
-a<b (unsigned) | | jal, jr $ra | Вызов/возврат процедуры |+
  
 === 4.2. Пример кода и разбор === === 4.2. Пример кода и разбор ===
  
-==== Знаковое сравнение ==== <code> li  +==== Знаковое сравнение ==== 
-+<code> 
-+li   $t0-
-, +li   $t1 1 
-− +slt  $at, $t0, $t1   $at = ($t0 < $t1) ? 1 : 0 
-+bnez $at, less_label # если $at != 0 — переход будет 
-+</code>
-+
-t0,−2lit1, 1 slt  +
-+
-+
-+
-at,t0, t1 # at = ( +
-+
-+
-+
-t0<t1) ? 1 : 0 bnez at, less_label # если at != 0 — переход будет </code>+
  
-==== Вызов функции ==== <code> jal my_func+==== Вызов функции ==== 
 +<code> 
 +jal my_func 
 +# ... 
 +my_func: 
 + ; ... 
 +jr $ra 
 +</code>
  
-... +==== Табличный переход ==== 
-my_func: ; ... jr $ra </code>+<code> 
 +sll $t1, $a0, 2 
 +la  $t2, jumptable 
 +addu $t1, $t1, $t2 
 +lw   $t3, 0($t1) 
 +jr   $t3 
 +</code>
  
-==== Табличный переход ==== <code> sll  +----
-+
-+
-+
-t1,a0, 2 la  +
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-t2,jumptableaddut1,  +
-+
-+
-+
-t1,t2 lw  +
-+
-+
-+
-+
-+
-t3,0(t1) jr $t3 </code>+
  
 === 5. Краткий итог сравнения ветвлений === === 5. Краткий итог сравнения ветвлений ===
  
-^ Архитектура Флаги/Механизм Условные переходы Рабочий пример +^ Архитектура Флаги/Механизм                Условные переходы                       | Рабочий пример     | 
-x86 EFLAGS (ZF, SF, OF, CF, PF) JE, JNE, JL, JG, JA, JB... cmp ax, bx; jl label +|-------------|-------------------------------|-----------------------------------------|--------------------| 
-ARM CPSR (N, Z, C, V) B<cond> (BEQ, BNE, BLT и др.) cmp r0, r1; blt label +x86         | EFLAGS (ZF, SF, OF, CF, PF)   | JE, JNE, JL, JG, JA, JB...              cmp ax, bx; jl label | 
-MIPS Нет флагов, сравн. в регистре beq, bne, slt+bnez slt  +ARM         | CPSR (N, Z, C, V)             | B<cond> (BEQ, BNE, BLT и др.)           | cmp r0, r1; blt label | 
-+MIPS        Нет флагов, сравн. в регистре beq, bne, slt+bnez                      slt $at, $a0, $a1bnez $at, l | 
-+ 
-+ 
-at,a0,  + 
-+---- 
-+
-+
-b +
-n +
-e +
-z +
-a1;bnezat, l+
 ===== 6. Разбор переходов с анализом флагов (на примере x86, ARM, MIPS) ===== ===== 6. Разбор переходов с анализом флагов (на примере x86, ARM, MIPS) =====
  
 === 6.1. x86: знаковое сравнение === === 6.1. x86: знаковое сравнение ===
  
-<code> mov eax, -3 ; FFFFFFFD mov ebx, 1 ; 00000001 cmp eax, ebx ; -3 - 1 = -4 (FFFFFFFC) jg more_label ; больше? (signed) jl less_label ; меньше? (signed) je equal_label ; равно? </code> +<code> 
-Флаги:+mov eax, -3         ; FFFFFFFD 
 +mov ebx, 1          ; 00000001 
 +cmp eax, ebx        ; -3 - 1 = -4 (FFFFFFFC) 
 +jg  more_label      ; больше? (signed) 
 +jl  less_label      ; меньше? (signed) 
 +je  equal_label     ; равно? 
 +</code>
  
-ZF = 0 (результат не ноль) +**Флаги:** 
-SF = 1 (отрицательное) +  - ZF = 0 (результат не ноль) 
-OF = 0 (нет переполнения) +  SF = 1 (отрицательное) 
-CF = 1 (беззнаковый "заём"+  OF = 0 (нет переполнения) 
-'''JG''' требует ZF=0 и SF=OF: 1 ≠ 0 — перехода НЕ будет.+  CF = 1 (беззнаковый "заём") 
 + 
 +'''JG''' требует ZF=0 и SF=OF: 1 ≠ 0 — перехода НЕ будет.  
 '''JL''' требует SF ≠ OF: 1 ≠ 0 — переход БУДЕТ! '''JL''' требует SF ≠ OF: 1 ≠ 0 — переход БУДЕТ!
  
-=== 6.2. x86: проверка на равенство === <code> mov eax, 7 mov ebx, 7 cmp eax, ebx je eq_label ; ZF=1 — переход БУДЕТ! jne neq_label ; ZF=0 — перехода не будет </code>+--- 
 + 
 +=== 6.2. x86: проверка на равенство === 
 +<code> 
 +mov eax, 7 
 +mov ebx, 7 
 +cmp eax, ebx 
 +je  eq_label  ; ZF=1 — переход БУДЕТ! 
 +jne neq_label ; ZF=0 — перехода не будет 
 +</code> 
 + 
 +---
  
 === 6.3. ARM: сравнение и разбор по флагам === === 6.3. ARM: сравнение и разбор по флагам ===
  
-<code> MOV R0, #5 MOV R1, #8 CMP R0, R1 ; результат -3, N=1, Z=0, V=0 BEQ label_eq ; Z=1? BNE label_ne ; Z=0? BLT label_lt ; N ≠ V? </code>+<code> 
 +MOV R0, #5 
 +MOV R1, #8 
 +CMP R0, R1      ; результат -3, N=1, Z=0, V=0 
 +BEQ label_eq    ; Z=1? 
 +BNE label_ne    ; Z=0? 
 +BLT label_lt    ; N ≠ V? 
 +</code> 
 == После CMP: == == После CMP: ==
 +  * N = 1 (отрицательно), V = 0, Z = 0  
 +  * BEQ — НЕ сработает; BNE — переход БУДЕТ; BLT — переход БУДЕТ.
 +
 +---
 +
 +=== 6.4. ARM: переполнение ===
 +<code>
 +MOV R2, #0x7FFFFFFF
 +ADD R2, R2, #1             ; R2 = 0x80000000 (отрицательное по знаку)
 +CMP R2, #0
 +BEQ label_zero             ; Z=0
 +BMI label_negative         ; N=1 — БУДЕТ переход!
 +BVS label_o                ; V=1, было переполнение — БУДЕТ переход!
 +</code>
 +
 +---
 +
 +=== 6.5. MIPS: ветвление через регистр-посредник ===
 +<code>
 +li   $t0, -2
 +li   $t1,  1
 +slt  $at, $t0, $t1   # if $t0 < $t1, $at = 1
 +bnez $at, less_label # если 1 — переход БУДЕТ!
 +</code>
  
-N = 1 (отрицательно), V = 0, Z = 0 +---
-BEQ — НЕ сработает; BNE — переход БУДЕТ; BLT — переход БУДЕТ. +
-=== 6.4. ARM: переполнение === <code> MOV R2, #0x7FFFFFFF ADD R2, R2, #1 ; R2 = 0x80000000 (отрицательное по знаку) CMP R2, #0 BEQ label_zero ; Z=0 BMI label_negative ; N=1 — БУДЕТ переход! BVS label_o ; V=1, было переполнение — БУДЕТ переход! </code>+
  
-=== 6.5. MIPS: ветвление через регистр-посредник === <code> li  
-t 
-0 
-, 
- 
-2 
-l 
-i 
-t0,−2lit1, 1 slt  
-a 
-t 
-, 
-at,t0, t1 # if t0 <  
-t 
-1 
-, 
-t1,at = 1 bnez $at, less_label # если 1 — переход БУДЕТ! </code> 
  • reverseenengineering/ветвления.1752676440.txt.gz
  • Последнее изменение: 2025/07/16 21:34
  • Lex