Реверсинг для начинающих
s1and1
В предыдущей статье мы работали с таким инструментом как дебаггер(x64dbg), для реверса программы, в этой статье я бы хотел посвятить так такому инструменту как IDA Pro. Статья предназначена новичкам!
IDA Pro представляет из себя простую в использовании, программу, позволяющая перевести бинарный код в дизассемблерный. На него очень много плагинов и она очень востребовательна у реверсеров.
P.S:Мы будем работать с x86 ассемблером(тот, на котором работает ваш пк)
Давайте попробуем написать простую программу на с++, скомпилированными разными компиляторами(msvc, mingw), в начале попробуем разобрать, как же будет выглядеть программа, после того, как мы его соберём:
Давайте для начала напишем простенькую с программу для того, чтобы разобраться как, что внутри нашего exe`шника
код:

Давайте скомпилируем его на этих компиляторах, дабы узнать, что получилось.
MSVC:

MinGW:

Существуют так называемые регистры*, я бы хотел обратить внимание на Регистры общего назначения(eax, ebx, ecx, edx). они используются для выполнений арифметических, математических операций(mov, inc, dec, sub, div, imul, lea и т.д.)
Так же регистры состоят из частей например регистр rax(в 32-битном режиме eax)
RAX - 64 битный (8 байт)
EAX - 32 битный (4 байта)
AX - 16 битный (2 байта)
AH, Al - 8 байтные (1 байт)
И так давайте разберём, что происходит в самом собранном файле.
`_main proc near` - означает, что тут начинается функция main(в си/с++ это начало программы)
`push esi` - означает, что мы добавляем на вершину стека(сохраняем) содержание в регистре esi
`push 400h` - означает, что мы добавляем в стэк значение 0x400, то есть 1024
`call ds:malloc` - тут вызываем функцию malloc(выделяем динамическую память), передавая в качестве аргумента 1024(размер выделяемой динамической памяти)
`mov esi, eax` - здесь мы помещаем результат вызова функции malloc(eax - адрес выделенной памяти)
`push esi` - тут та же самая история с malloc, мы добавляем в стэк значение которое лежит в esi(то есть помещённый указатель eax)
`push offset Format ; "%s"` - тут мы передаём формат строки %s означает просто строка
`call sub_FD1050` - здесь мы вызываем функцию по адресу 0xFD1050, то есть компилятор создал функцию, через которого и обращается к vfscanf
`push esi` - то же самое что и при вызове с malloc, только теперь она передаётся в качестве аргумента другой функции(printf)
`push offset Format ; "%s"` - то же самое, но только для вызова printf
`call sub_FD1020` - тут мы вызываем функцию, которая находится по адресу 0xFD1020, она, как в предыдущей функции является "трамплином" между функциями си и с++
`add esp, 14h` - увеличиваем указатель стека на 0x14(20), для очистки стека
`xor eax, eax` - тут, мы выполняем операцию XOR(ИЛИ), в этом случае, он обнуляет значение регистра eax на 0, используется xor потому, что он короче на 2 байта
`pop esi` - помните в самом начале мы добавили на вершину стэка значение регистра esi, так вот, сейчас мы его получаем
`retn` - означает, что функция main была успешно завершена
`_main endp` - означает, что заканчиваем функцию main
В этом примере вам показал, как, на уровне ассемблера, работает программа.
`_main proc near` -
`push ebp` - добавляем на вершину стека регистр ebp(это, как в прошлом примере, позволяет сохранить значение ebp)
`mov ebp, esp` - сдвигаем значение регистра esp в регистр ebp(создаём фрейм стека* для данной функции)
`and esp, 0FFFFFFF0h` - выравниваем esp по границе на 16 байт(0x0FFFFFFF0 означает -16)
`sub esp, 20h` - выделяем 32 байт(0x20) в стэке
`call ___main` - вызывается функция ___main, которая нужна для инициализации статических объектов
`mov dword ptr [esp], 400h` - записывает значение 0x400(1024 в стэк)
`call _malloc` - вызываем функцию для выделения самой динамической памяти
`mov [esp+1Ch], eax` - как говорилось выше, регистры 32-битного режима имеют 4 байта размер, 1Ch(то есть 0x1C(то есть 12)) означает, что значение регистра eax(адрес начала выделенной памяти) ставиться в стэк после трёх таких же регистров в стэке, почему трёх?(12/3=4)
`mov eax, [esp+1Ch]` - тут происходит что-то странное, тут мы помещаем значение адреса 1С(12)(куда был скопирован eax) в eax(странный Min-GW) :)
`mov [esp+4], eax` - здесь мы помещаем значение из eax в стэк после одного
`mov dword ptr [esp], offset Format ; "%s"` - тут мы в начало стека передаём формат строки
`call _scanf` - вызов функции _scanf
`mov eax, [esp+1Ch]` - тут означает, что мы берём то самое значение в стэке, которое сохранили в начале выполнения программы
`mov [esp+4], eax` - тут, то значение, которое мы получили ставим после одного регистра в стэке
`mov dword ptr [esp], offset Format ; "%s"` - тут мы в начало стек передаём формат строки
`call _printf` - вызываем printf
`mov eax, 0` - тут мы в регистр eax записываем 0(честно говоря можно было xor eax, eax)
`leave` - тут происходит восстановление значения регистра ebp из стека и перемещение значения esp в ebp.
`retn` - тут происходит возврат из функции и восстановление адреса возврата.
`_main endp` - конец main
Для IDA Pro, x64dbg существуют много плагинов(например snowman), которые смогу облегчить вам дизассемблирование и анализ программы. Я бы хотел вам продемонстрировать работу плагина одного плагина Hex-Rays Decompiler, для чего он нужен? Hex-Rays Decompiler используется чтобы перевести из непонятного ассемблера в псевдо-си синтаксис(иногда это может помочь если вы не привыкли работать с ассемблером, но иногда это не будет работать как надо).
Чтобы попробовать "Превратить" ассемблер в си нужно просто нажать на клавишу F5 и вы получите псевдо си код
давайте посмотрим, как бы выглядела программа, которую я написал. если я воспользуюсь этим плагином:
Min-GW:

MSVC:

Всё вышесказанное бы хотел подытожить тем что ассемблер - не простая штука, как показалось на первый взгляд. Я бы порекомендовал для начала прочитать пару книг про ассемблер, чтобы приступить к реверс инжинирингу например книгу от Юрия Магды Ассемблер для процессоров Intel Pentium
Источники
https://en.m.wikibooks.org/wiki/X86_Disassembly/Functions_and_Stack_Frames - разбор, как устроены функции в MinGW
https://metanit.com/assembler/tutorial/1.3.php - регистры процессора
Книга реверс для начинающих от Дениса Юричева