Reverse Engineering для начинающих
Dennis Yurichev
Computers & Technology
Reverse Engineering для начинающих
Free
Description
Contents
Reviews


У термина «reverse engineering» несколько популярных значений: 

1) исследование скомпилированных программ; 

2) ска- нирование трехмерной модели для последующего копирования; 

3) восстановление структуры СУБД. 

Настоящий сборник заметок связан с первым значением.

Рассмотренные темы

x86/x64, ARM/ARM64, MIPS, Java/JVM.

Затронутые темы

Oracle RDBMS , Itanium, донглы для защиты от копирования , LD_PRELOAD , переполнение стека, ELF9, формат файла PE в win32 , x86-64 , критические секции, системные вызовы , TLS10, адресно-независимый код, profile- guided optimization , C++ STL , OpenMP , SEH.

 

Also in English.
Language
Russian
ISBN
0262033844
I Образцы кода
Краткое введение в CPU
Несколько слов о разнице между ISA
Простейшая функция
x86
ARM
MIPS
Еще кое-что об именах инструкций и регистров в MIPS
Hello, world!
x86
MSVC
GCC
GCC: Синтаксис AT&T
x86-64
MSVC — x86-64
GCC — x86-64
GCC — ещё кое-что
ARM
Неоптимизирующий Keil 6/2013 (Режим ARM)
Неоптимизирующий Keil 6/2013 (Режим Thumb)
Оптимизирующий Xcode 4.6.3 (LLVM) (Режим ARM)
Оптимизирующий Xcode 4.6.3 (LLVM) (Режим Thumb-2)
ARM64
MIPS
О "глобальном указателе" ("global pointer")
Оптимизирующий GCC
Неоптимизирующий GCC
Роль стекового фрейма в этом примере
Оптимизирующий GCC: загрузим в GDB
Вывод
Упражнения
Упражнение #1
Упражнение #2
Пролог и эпилог функций
Рекурсия
Стек
Почему стек растет в обратную сторону?
Для чего используется стек?
Сохранение адреса возврата управления
Передача параметров функции
Хранение локальных переменных
x86: Функция alloca()
(Windows) SEH
Защита от переполнений буфера
Автоматическое освобождение данных в стеке
Разметка типичного стека
Мусор в стеке
Упражнения
Упражнение #1
Упражнение #2
printf() с несколькими аргументами
x86
x86: 3 аргумента
x64: 8 аргументов
ARM
ARM: 3 аргумента
ARM: 8 аргументов
MIPS
3 аргумента
8 аргументов
Вывод
Кстати
scanf()
Простой пример
Об указателях
x86
MSVC + OllyDbg
x64
ARM
MIPS
Глобальные переменные
MSVC: x86
MSVC: x86 + OllyDbg
GCC: x86
MSVC: x64
ARM: Оптимизирующий Keil 6/2013 (Режим Thumb)
ARM64
MIPS
Проверка результата scanf()
MSVC: x86
MSVC: x86: IDA
MSVC: x86 + OllyDbg
MSVC: x86 + Hiew
MSVC: x64
ARM
MIPS
Упражнение
Упражнения
Упражнение #1
Доступ к переданным аргументам
x86
MSVC
MSVC + OllyDbg
GCC
x64
MSVC
GCC
GCC: uint64_t вместо int
ARM
Неоптимизирующий Keil 6/2013 (Режим ARM)
Оптимизирующий Keil 6/2013 (Режим ARM)
Оптимизирующий Keil 6/2013 (Режим Thumb)
ARM64
MIPS
Ещё о возвращаемых результатах
Попытка использовать результат функции возвращающей void
Что если не использовать результат функции?
Возврат структуры
Указатели
Пример с глобальными переменными
Пример с локальными переменными
Вывод
Оператор GOTO
Мертвый код
Упражнение
Условные переходы
Простой пример
x86
ARM
MIPS
Вычисление абсолютной величины
Оптимизирующий MSVC
Оптимизирующий Keil 6/2013: Режим Thumb
Оптимизирующий Keil 6/2013: Режим ARM
Неоптимизирующий GCC 4.9 (ARM64)
MIPS
Версия без переходов?
Тернарный условный оператор
x86
ARM
ARM64
MIPS
Перепишем, используя обычный if/else
Вывод
Поиск минимального и максимального значения
32-bit
64-bit
MIPS
Вывод
x86
ARM
MIPS
Без инструкций перехода
Упражнение
switch()/case/default
Если вариантов мало
x86
ARM: Оптимизирующий Keil 6/2013 (Режим ARM)
ARM: Оптимизирующий Keil 6/2013 (Режим Thumb)
ARM64: Неоптимизирующий GCC (Linaro) 4.9
ARM64: Оптимизирующий GCC (Linaro) 4.9
MIPS
Вывод
И если много
x86
ARM: Оптимизирующий Keil 6/2013 (Режим ARM)
ARM: Оптимизирующий Keil 6/2013 (Режим Thumb)
MIPS
Вывод
Когда много case в одном блоке
MSVC
GCC
ARM64: Оптимизирующий GCC 4.9.1
Fall-through
MSVC x86
ARM64
Упражнения
Упражнение #1
Циклы
Простой пример
x86
x86: OllyDbg
x86: tracer
ARM
MIPS
Ещё кое-что
Функция копирования блоков памяти
Простейшая реализация
ARM в режиме ARM
MIPS
Векторизация
Вывод
Упражнения
Упражнение #1
Упражнение #2
Упражнение #3
Упражнение #4
Простая работа с Си-строками
strlen()
x86
ARM
MIPS
Упражнения
Упражнение #1
Замена одних арифметических инструкций на другие
Умножение
Умножение при помощи сложения
Умножение при помощи сдвигов
Умножение при помощи сдвигов, сложений и вычитаний
Деление
Деление используя сдвиги
Упражнения
Упражнение #2
Работа с FPU
IEEE 754
x86
ARM, MIPS, x86/x64 SIMD
Си/Си++
Простой пример
x86
ARM: Оптимизирующий Xcode 4.6.3 (LLVM) (Режим ARM)
ARM: Оптимизирующий Keil 6/2013 (Режим Thumb)
ARM64: Оптимизирующий GCC (Linaro) 4.9
ARM64: Неоптимизирующий GCC (Linaro) 4.9
MIPS
Передача чисел с плавающей запятой в аргументах
x86
ARM + Неоптимизирующий Xcode 4.6.3 (LLVM) (Режим Thumb-2)
ARM + Неоптимизирующий Keil 6/2013 (Режим ARM)
ARM64 + Оптимизирующий GCC (Linaro) 4.9
MIPS
Пример с сравнением
x86
ARM
ARM64
MIPS
Стек, калькуляторы и обратная польская запись
x64
Упражнения
Упражнение #1
Упражнение #2
Массивы
Простой пример
x86
ARM
MIPS
Переполнение буфера
Чтение за пределами массива
Запись за пределы массива
Защита от переполнения буфера
Оптимизирующий Xcode 4.6.3 (LLVM) (Режим Thumb-2)
Еще немного о массивах
Массив указателей на строки
x64
32-битный ARM
ARM64
MIPS
Переполнение массива
Многомерные массивы
Пример с двумерным массивов
Работа с двухмерным массивом как с одномерным
Пример с трехмерным массивом
Ещё примеры
Набор строк как двухмерный массив
32-bit ARM
ARM64
MIPS
Вывод
Вывод
Упражнения
Упражнение #1
Упражнение #2
Упражнение #3
Упражнение #4
Упражнение #5
Работа с отдельными битами
Проверка какого-либо бита
x86
ARM
Установка и сброс отдельного бита
x86
ARM + Оптимизирующий Keil 6/2013 (Режим ARM)
ARM + Оптимизирующий Keil 6/2013 (Режим Thumb)
ARM + Оптимизирующий Xcode 4.6.3 (LLVM) (Режим ARM)
ARM: ещё об инструкции BIC
ARM64: Оптимизирующий GCC (Linaro) 4.9
ARM64: Неоптимизирующий GCC (Linaro) 4.9
MIPS
Сдвиги
Установка и сброс отдельного бита: пример с FPU
Кое-что об операции XOR
x86
MIPS
ARM
Подсчет выставленных бит
x86
x64
ARM + Оптимизирующий Xcode 4.6.3 (LLVM) (Режим ARM)
ARM + Оптимизирующий Xcode 4.6.3 (LLVM) (Режим Thumb-2)
ARM64 + Оптимизирующий GCC 4.9
ARM64 + Неоптимизирующий GCC 4.9
MIPS
Вывод
Проверка определенного бита (известного на стадии компиляции)
Проверка определенного бита (заданного во время исполнения)
Установка определенного бита (известного во время компиляции)
Установка определенного бита (заданного во время исполнения)
Сброс определенного бита (известного во время компиляции)
Сброс определенного бита (заданного во время исполнения)
Упражнения
Упражнение #1
Упражнение #2
Упражнение #3
Упражнение #4
Линейный конгруэнтный генератор
x86
x64
32-bit ARM
MIPS
Перемещения в MIPS ("relocs")
Версия этого примера для многопоточной среды
Структуры
MSVC: Пример SYSTEMTIME
OllyDbg
Замена структуры массивом
Выделяем место для структуры через malloc()
UNIX: struct tm
Linux
ARM
MIPS
Структура как набор переменных
Структура как массив 32-битных слов
Структура как массив байт
Упаковка полей в структуре
x86
ARM
MIPS
Еще кое-что
Вложенные структуры
OllyDbg
Работа с битовыми полями в структуре
Пример CPUID
Работа с типом float как со структурой
Упражнения
Упражнение #1
Упражнение #2
Объединения (union)
Пример генератора случайных чисел
x86
MIPS
ARM (Режим ARM)
Вычисление машинного эпсилона
x86
ARM64
MIPS
Вывод
Быстрое вычисление квадратного корня
Указатели на функции
MSVC
MSVC + OllyDbg
MSVC + tracer
MSVC + tracer (code coverage)
GCC
GCC + GDB (с исходными кодами)
GCC + GDB (без исходных кодов)
64-битные значения в 32-битной среде
Возврат 64-битного значения
x86
ARM
MIPS
Передача аргументов, сложение, вычитание
x86
ARM
MIPS
Умножение, деление
x86
ARM
MIPS
Сдвиг вправо
x86
ARM
MIPS
Конвертирование 32-битного значения в 64-битное
x86
ARM
MIPS
SIMD
Векторизация
Пример сложения
Пример копирования блоков
Реализация strlen() при помощи SIMD
64 бита
x86-64
ARM
Числа с плавающей запятой
Работа с числами с плавающей запятой используя SIMD
Простой пример
x64
x86
Передача чисел с плавающей запятой в аргументах
Пример с сравнением
x64
x86
Вычисление машинного эпсилона: x64 и SIMD
И снова пример генератора случайных чисел
Итог
Кое-что специфичное для ARM
Знак номера (#) перед числом
Режимы адресации
Загрузка констант в регистр
32-битный ARM
ARM64
Релоки в ARM64
Кое-что специфичное для MIPS
Загрузка констант в регистр
Книги и прочие материалы о MIPS
II Важные фундаментальные вещи
Представление знака в числах
Endianness (порядок байт)
Big-endian (от старшего к младшему)
Little-endian (от младшего к старшему)
Пример
Bi-endian (переключаемый порядок)
Конвертирование
Память
CPU
Предсказатели переходов
Зависимости между данными
Хеш-функции
Как работает односторонняя функция?
III Более сложные примеры
Конвертирование температуры
Целочисленные значения
Оптимизирующий MSVC 2012 x86
Оптимизирующий MSVC 2012 x64
Числа с плавающей запятой
Числа Фибоначчи
Пример #1
Пример #2
Итог
Пример вычисления CRC32
Пример вычисления адреса сети
calc_network_address()
form_IP()
print_as_IP()
form_netmask() и set_bit()
Итог
Циклы: несколько итераторов
Три итератора
Два итератора
Случай Intel C++ 2011
Duff's device
Деление на 9
x86
ARM
Оптимизирующий Xcode 4.6.3 (LLVM) (Режим ARM)
Оптимизирующий Xcode 4.6.3 (LLVM) (Режим Thumb-2)
Неоптимизирующий Xcode 4.6.3 (LLVM) и Keil 6/2013
MIPS
Как это работает
Больше теории
Определение делителя
Вариант #1
Вариант #2
Упражнение #1
Конверсия строки в число (atoi())
Простой пример
Оптимизирующий MSVC 2013 x64
Оптимизирующий GCC 4.9.1 x64
Оптимизирующий Keil 6/2013 (Режим ARM)
Оптимизирующий Keil 6/2013 (Режим Thumb)
Оптимизирующий GCC 4.9.1 ARM64
Немного расширенный пример
Оптимизирующий GCC 4.9.1 x64
Оптимизирующий Keil 6/2013 (Режим ARM)
Упражнение
Inline-функции
Функции работы со строками и памятью
strcmp()
strlen()
strcpy()
memset()
memcpy()
memcmp()
Скрипт для IDA
C99 restrict
Функция abs() без переходов
Оптимизирующий GCC 4.9.1 x64
Оптимизирующий GCC 4.9 ARM64
Функции с переменным количеством аргументов (variadic)
Вычисление среднего арифметического
Соглашение о вызовах cdecl
Соглашения о вызовах на основе регистров
Случай с функцией vprintf()
Обрезка строк
x64: Оптимизирующий MSVC 2013
x64: Неоптимизирующий GCC 4.9.1
x64: Оптимизирующий GCC 4.9.1
ARM64: Неоптимизирующий GCC (Linaro) 4.9
ARM64: Оптимизирующий GCC (Linaro) 4.9
ARM: Оптимизирующий Keil 6/2013 (Режим ARM)
ARM: Оптимизирующий Keil 6/2013 (Режим Thumb)
MIPS
Функция toupper()
x64
Две операции сравнения
Одна операция сравнения
ARM
GCC для ARM64
Итог
Неверно дизассемблированный код
Дизассемблирование началось в неверном месте (x86)
Как выглядят случайные данные в дизассемблированном виде?
Обфускация
Текстовые строки
Исполняемый код
Вставка мусора
Замена инструкций на раздутые эквиваленты
Всегда исполняющийся/никогда не исполняющийся код
Сделать побольше путаницы
Использование косвенных указателей
Виртуальная машина / псевдо-код
Еще кое-что
Упражнения
Упражнение #1
Си++
Классы
Простой пример
Наследование классов
Инкапсуляция
Множественное наследование
Виртуальные методы
ostream
References
STL
std::string
std::list
std::vector
std::map и std::set
Отрицательные индексы массивов
Windows 16-bit
Пример#1
Пример #2
Пример #3
Пример #4
Пример #5
Пример #6
Глобальные переменные
IV Java
Java
Введение
Возврат значения
Простая вычисляющая функция
Модель памяти в JVM
Простой вызов функций
Вызов beep()
Линейный конгруэнтный ГПСЧ
Условные переходы
Передача аргументов
Битовые поля
Циклы
switch()
Массивы
Простой пример
Суммирование элементов массива
Единственный аргумент main() это также массив
Заранее инициализированный массив строк
Функции с переменным кол-вом аргументов (variadic)
Двухмерные массивы
Трехмерные массивы
Итоги
Строки
Первый пример
Второй пример
Исключения
Классы
Простейшая модификация
Первый пример
Второй пример
Итоги
V Поиск в коде того что нужно
Идентификация исполняемых файлов
Microsoft Visual C++
Name mangling
GCC
Name mangling
Cygwin
MinGW
Intel FORTRAN
Watcom, OpenWatcom
Name mangling
Borland
Delphi
Другие известные DLL
Связь с внешним миром (win32)
Часто используемые функции Windows API
tracer: Перехват всех функций в отдельном модуле
Строки
Текстовые строки
Си/Си++
Borland Delphi
Unicode
Base64
Сообщения об ошибках и отладочные сообщения
Подозрительные магические строки
Вызовы assert()
Константы
Magic numbers
DHCP
Поиск констант
Поиск нужных инструкций
Подозрительные паттерны кода
Инструкции XOR
Вручную написанный код на ассемблере
Использование magic numbers для трассировки
Прочее
Общая идея
Си++
Некоторые паттерны в бинарных файлах
Сравнение "снимков" памяти
Реестр Windows
Блинк-компаратор
VI Специфичное для ОС
Способы передачи аргументов при вызове функций
cdecl
stdcall
Функции с переменным количеством аргументов
fastcall
GCC regparm
Watcom/OpenWatcom
thiscall
x86-64
Windows x64
Linux x64
Возвращение переменных типа float, double
Модификация аргументов
Указатель на аргумент функции
Thread Local Storage
Вернемся к линейному конгруэнтному генератору
Win32
Linux
Системные вызовы (syscall-ы)
Linux
Windows
Linux
Адресно-независимый код
Windows
Трюк с LD_PRELOAD в Linux
Windows NT
CRT (win32)
Win32 PE
Терминология
Базовый адрес
Subsystem
Версия ОС
Секции
Релоки
Экспорты и импорты
Ресурсы
.NET
TLS
Инструменты
Further reading
Windows SEH
Забудем на время о MSVC
Теперь вспомним MSVC
Windows x64
Больше о SEH
Windows NT: Критические секции
VII Инструменты
Дизассемблер
IDA
Отладчик
OllyDbg
GDB
tracer
Трассировка системных вызовов
strace / dtruss
Декомпиляторы
Прочие инструменты
VIII Примеры RE-задач из реальности
Шутка с task manager (Windows Vista)
Использование LEA для загрузки значений
Шутка с игрой Color Lines
Сапёр (Windows XP)
Упражнения
Ручная декомпиляция + использование SMT-солвера Z3
Ручная декомпиляция
Попробуем Z3 SMT-солвер
Донглы
Пример #1: MacOS Classic и PowerPC
Пример #2: SCO OpenServer
Дешифровка сообщений об ошибке
Пример #3: MS-DOS
"QR9": Любительская криптосистема, вдохновленная кубиком Рубика
SAP
Касательно сжимания сетевого траффика в клиенте SAP
Функции проверки пароля в SAP 6.0
Oracle RDBMS
Таблица V$VERSION в Oracle RDBMS
Таблица X$KSMLRU в Oracle RDBMS
Таблица V$TIMER в Oracle RDBMS
Вручную написанный на ассемблере код
Тестовый файл EICAR
Демо
10 PRINT CHR$(205.5+RND(1)); : GOTO 10
Версия 42-х байт от Trixter
Моя попытка укоротить версию Trixter: 27 байт
Использование случайного мусора в памяти как источника случайных чисел
Вывод
Множество Мандельброта
Теория
Вернемся к демо
Моя "исправленная" версия
IX Примеры разбора закрытых (proprietary) форматов файлов
Примитивное XOR-шифрование
Norton Guide: простейшее однобайтное XOR-шифрование
Энтропия
Простейшее четырехбайтное XOR-шифрование
Упражнение
Файл сохранения состояния в игре Millenium
Oracle RDBMS: .SYM-файлы
Oracle RDBMS: .MSB-файлы
Вывод
X Прочее
npad
Модификация исполняемых файлов
Текстовые строки
x86-код
Compiler intrinsic
Аномалии компиляторов
OpenMP
MSVC
GCC
Itanium
Модель памяти в 8086
Перестановка basic block-ов
Profile-guided optimization
XI Что стоит почитать
Книги
Windows
Си/Си++
x86 / x86-64
ARM
Криптография
Блоги
Windows
Прочее
XII Упражнения
Уровень 1
Упражнение 1.4
Уровень 2
Упражнение 2.1
Оптимизирующий MSVC 2010 x86
Оптимизирующий MSVC 2012 x64
Упражнение 2.4
Оптимизирующий MSVC 2010
GCC 4.4.1
Оптимизирующий Keil (Режим ARM)
Оптимизирующий Keil (Режим Thumb)
Оптимизирующий GCC 4.9.1 (ARM64)
Оптимизирующий GCC 4.4.5 (MIPS)
Упражнение 2.6
Оптимизирующий MSVC 2010
Оптимизирующий Keil (Режим ARM)
Оптимизирующий Keil (Режим Thumb)
Оптимизирующий GCC 4.9.1 (ARM64)
Оптимизирующий GCC 4.4.5 (MIPS)
Упражнение 2.13
Оптимизирующий MSVC 2012
Keil (Режим ARM)
Keil (Режим Thumb)
Оптимизирующий GCC 4.9.1 (ARM64)
Оптимизирующий GCC 4.4.5 (MIPS)
Упражнение 2.14
MSVC 2012
Keil (Режим ARM)
GCC 4.6.3 for Raspberry Pi (Режим ARM)
Оптимизирующий GCC 4.9.1 (ARM64)
Оптимизирующий GCC 4.4.5 (MIPS)
Упражнение 2.15
Оптимизирующий MSVC 2012 x64
Оптимизирующий GCC 4.4.6 x64
Оптимизирующий GCC 4.8.1 x86
Keil (Режим ARM): для процессора Cortex-R4F
Оптимизирующий GCC 4.9.1 (ARM64)
Оптимизирующий GCC 4.4.5 (MIPS)
Упражнение 2.16
Оптимизирующий MSVC 2012 x64
Оптимизирующий Keil (Режим ARM)
Оптимизирующий Keil (Режим Thumb)
Неоптимизирующий GCC 4.9.1 (ARM64)
Оптимизирующий GCC 4.9.1 (ARM64)
Неоптимизирующий GCC 4.4.5 (MIPS)
Упражнение 2.17
Упражнение 2.18
Упражнение 2.19
Упражнение 2.20
Уровень 3
Упражнение 3.2
Упражнение 3.3
Упражнение 3.4
Упражнение 3.5
Упражнение 3.6
Упражнение 3.8
crackme / keygenme
Послесловие
Вопросы?
Приложение
x86
Терминология
Регистры общего пользования
RAX/EAX/AX/AL
RBX/EBX/BX/BL
RCX/ECX/CX/CL
RDX/EDX/DX/DL
RSI/ESI/SI/SIL
RDI/EDI/DI/DIL
R8/R8D/R8W/R8L
R9/R9D/R9W/R9L
R10/R10D/R10W/R10L
R11/R11D/R11W/R11L
R12/R12D/R12W/R12L
R13/R13D/R13W/R13L
R14/R14D/R14W/R14L
R15/R15D/R15W/R15L
RSP/ESP/SP/SPL
RBP/EBP/BP/BPL
RIP/EIP/IP
CS/DS/ES/SS/FS/GS
Регистр флагов
FPU регистры
Регистр управления
Регистр статуса
Tag Word
SIMD регистры
MMX регистры
SSE и AVX регистры
Отладочные регистры
DR6
DR7
Инструкции
Префиксы
Наиболее часто используемые инструкции
Реже используемые инструкции
Инструкции FPU
Инструкции с печатаемым ASCII-опкодом
ARM
Терминология
Версии
32-битный ARM (AArch32)
Регистры общего пользования
Current Program Status Register (CPSR)
Регистры VPF (для чисел с плавающей точкой) и NEON
64-битный ARM (AArch64)
Регистры общего пользования
Инструкции
Таблица условных кодов
MIPS
Регистры
Регистры общего пользования GPR
Регистры для работы с числами с плавающей точкой
Инструкции
Инструкции перехода
Некоторые библиотечные функции GCC
Некоторые библиотечные функции MSVC
Cheatsheets
IDA
OllyDbg
MSVC
GCC
GDB
Ответы на задачи
По главам
Глава "Hello, world!"
Глава "Стек"
Глава "scanf()"
Глава "switch()/case/default"
Упражнение #1
Глава "Циклы"
Упражнение #3
Упражнение #4
Глава "Простая работа с Си-строками"
Глава " Замена одних арифметических инструкций на другие "
Глава "Работа с FPU"
Глава "Массивы"
Глава "Работа с отдельными битами"
Глава "Структуры"
Глава "Обфускация"
Глава "Деление на 9"
Уровень 1
Упражнение 1.1
Упражнение 1.4
Уровень 2
Упражнение 2.1
Упражнение 2.4
Упражнение 2.6
Упражнение 2.13
Упражнение 2.14
Упражнение 2.15
Упражнение 2.16
Упражнение 2.17
Упражнение 2.18
Упражнение 2.19
Упражнение 2.20
Уровень 3
Упражнение 3.2
Упражнение 3.3
Упражнение 3.4
Упражнение 3.5
Упражнение 3.6
Упражнение 3.8
Прочее
Задача "Сапёр (Windows XP)"
Список принятых сокращений
Глоссарий
Предметный указатель
Библиография
The book hasn't received reviews yet.
You May Also Like
Pro Git
Free
Scott Chacon
Pro Git