Русский
Русский
English
Статистика
Реклама

Дизассемблируем код на Си switch() case assembler disass()

Доброго времени суток.

Сегодня мы будем смотреть дизассемблированный код инструкций if, for, while, swich, которые написаны на языке Си.

1605795529033.png1605795529033.png

Инcтрукция if

Данную инструкцию довольно просто отличить в дизассемблированном виде от других инструкций. Её отличительное свойство - одиночные инструкции условного перехода je, jne и другие команды jump.

1605790962062.png1605790962062.png1605790989407.png1605790989407.png

Напишем небольшую программу на языке Си и дизассемблируем её с помощью radare2. Разницы между IDA PRO и radare2 при дизассемблировании этих программ не было обнаружено, поэтому я воспользуюсь radare2. Вы можете использовать IDA PRO.

IDA PRO

2020-11-17_08-22.png2020-11-17_08-22.png2020-11-17_08-23.png2020-11-17_08-23.png

radare2

1605792900362.png1605792900362.png

Код на Си

#include <stdio.h>void main() {    int x = 1;    int y = 2;    if(x == y) {        printf("x = y\n");    }    else{        printf("x != y\n");    }}

Компилируем при помощи gcc. Команда gcc -m32 prog_if.c -o prog_if. -m32 озночает, что компилироваться код будет под архитектуру x86.

Чтобы посмотреть на код в radare2, напишем команду r2 prog_if. Далее прописываем aaa для анализа кода и переходим к функции main s main. Посмотрим на код с помощью команды pdf.

Дизассемблированный вариант в radare2

1605792900362.png1605792900362.png

Первым делом в программе происходит объявление переменных ( int x; int y ), а затем значение 1 перемещается в varch (это переменная x) и значение 2 в var10h (это переменная y). Далее идёт сравнение (cmp) 1 и 2 (cmp edx, dword [var_10h]). Эти значения не равны. Значит jne ( jump if noe equal) перейдёт по адресу 0x000011e1. Проще всего инструкцию if запомнить и опрелелить в режиме графов (команда VV для для radare2 или клавиша пробел для IDA).

Режим графов

1605792914861.png1605792914861.png

Немного усложним задачу. Добавим вложенные инструкции. Попробуйте проанализировать этот код.

Код на Си

#include <stdio.h>void main() {    int x = 0;    int y = 1;    int z = 2;    if(x == y) {        if(z == 0) {        printf("z = 0; x = y\n");        }        else{            printf("z = 0; x != y\n");        }    }    else {        if(z == 0) {            printf("z = zero and x != y.\n");        } else {            printf("z non-zero and x != y.\n");        }    }}

Дизассемблированный вариант в radare2

1605792935104.png1605792935104.png

Режим графов

1605792950680.png1605792950680.png

В режиме графов это воспринимать намного проще.

Инструкция for

Циклы for всегда состоят из четырех этапов: инициализации, сравнения, выполнения инструкций и инкремента/декремента. По этим четырём этапом мы будем распозновать for в ассемблерном коде.

Код на Си

#include <stdio.h>void main() {    int x;    for(x = 0; x < 100; x++) {        printf("x = %d", x);    }}

Дизассемблированный вариант в radare2

1605792973718.png1605792973718.png

1 - инициализации переменной var_ch (x = 0)
2 - сравнение, а затем jle. ( пока x не будет меньше или равен 2, выполнять цикл.)
3 - выполнения инструкций (printf)
4 - инкрмент переменной var_
ch (++x)

Режим графов

1605792987678.png1605792987678.png

Инструкция while

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

Код на Си

#include <stdio.h>int func_1(int x);int change_status();int main() {    int status = 0;    while(status == 0) {        printf("int e = %d", func_1(5) );        status = change_status();    }    return 0;}int change_status() {    return 1;}int func_1(int x) {    int c;    int e;    int l;    c = 1 + 2;    e = x / 5;    l = 4 - 2;    return e;}

Дизассемблированный вариант в radare2

1605793002542.png1605793002542.png

1 - инициализации переменной var_4h (status = 0)
2 - сравнение, а затем je. ( пока x равен 0, выполнять цикл.)
3 - выполнения инструкций (func
1, printf, change_status)

Режим графов

1605793019409.png1605793019409.png

Инструкция switch

Конструкция switch обычно компилируется двумя способами: по примеру условного выражения или как таблица переходов.

Компиляция по примеру условного выражения

Код на Си

#include <stdio.h>int main() {    int i = 3;    switch(i) {        case 1:            printf("CASE_1 i = %d", i+4);            break;        case 2:            printf("CASE_2 i = %d", i+9);            break;        case 3:            printf("CASE_3 i = %d", i+14);            break;    }    return 0;}

Дизассемблированный вариант в radare2

1605793045836.png1605793045836.png

1 - инициализации переменной var_4h (i = 3)
2 - выполнения инструкций (add, printf)

Чтобы понять какой "case" выбран, происходит сравниение (cmp, а затем je, jne) переменной i с значением case.

Режим графов

1605793347813.png1605793347813.pngscreen13.pngscreen13.pngscreen_13_2.pngscreen_13_2.png

Глядя на этот код, сложно (если вообще возможно) сказать, что представлял собой оригинальный исходный текст конструкцию switch или последовательность выражений if . В обоих случаях код выглядит одинаково, поскольку оба выражения используют множество инструкций cmp и je или jne.

Таблица переходов

Следующий пример ассемблерного кода часто можно встретить в больших смежных выражениях switch. Мы добавим case 4 и инструкцию по умолчанию.

Код на Си

#include <stdio.h>int main() {    int i = 3;    switch(i) {        case 1:            printf("CASE_1 i = %d", i+4);            break;        case 2:            printf("CASE_2 i = %d", i+9);            break;        case 3:            printf("CASE_3 i = %d", i+14);            break;        case 4:            printf("CASE_3 i = %d", i+19);            break;        default:            break;    }    return 0;}

Дизассемблированный вариант в radare2

1605793648917.png1605793648917.png1605793656018.png1605793656018.png

1 - инициализации переменной var_4h (i = 3)
2 - выполнения инструкций (add, printf)

Вот этот дизасcемблированный код довольно сложно быстро отличить от if и вообще понять что и как тут. В режиме графов всё будет более понятно.

Режим графов

1605793750977.png1605793750977.png1605793673414.png1605793673414.png1605793684884.png1605793684884.png1605793691266.png1605793691266.png

Режим графов - ваш друг в дизасcемблировании :)

На этом всё. Рекомендую попробовать самому написать программы на Си, скомпилировать и изучить дизасcемблированный код. Практика и ещё раз практика!

Спасибо за внимание. Не болейте.

Источник: habr.com
К списку статей
Опубликовано: 19.11.2020 20:15:16
0

Сейчас читают

Комментариев (0)
Имя
Электронная почта

Assembler

Отладка

C

Реверс-инжиниринг

Ассемблер

Radare2

Reverse-engineering

Циклы

Информационная безопасность

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru