Часть 3
Last updated
Last updated
Загрузчик
Мы уже видели, что когда в IDA мы открываем исполняемый файл, тот же самый файл открывается в ЗАГРУЗЧИКЕ, который является статическим анализатором того же самого файла.
Мы будем анализировать его части и характеристики, большая часть того, что мы видели до настоящего времени, будут применимы и к ЗАГРУЗЧИКУ и для ОТЛАДЧИКА. В случае, если что-то будет отличаться или не похоже на общий случай, я упомяну это.
Очевидно, то, что в ЗАГРУЗЧИКЕ программа абсолютно не выполняется, но она анализируется, и создаётся база данных с информацией этого файла, и это значительное отличие относительно ОТЛАДЧИКА.
В ЗАГРУЗЧИКЕ нет ни окна РЕГИСТРОВ, ни окна СТЕКА, ни списка модулей, которые загружены в память. Это вещи, существуют при выполнении и отладке программы.
После загрузки Cruehead Crackme (CRACKME.EXE), если мы посмотрим на список процессов , то увидим, что он не работает и никогда не выполняется, пока мы не откроем отладчик IDA.
Это очень полезно для определенного использования, например как анализ вредоноса, эксплоита и т.д. , потому что мы не всегда сможем получить доступ к некоторой функции, для этого мы должны изучить отладку, в то время как в ЗАГРУЗЧИКЕ мы можем проанализировать любую из функций программы, это не имеет значения, если мы не знаем как её вызывать и пользоваться ей.
Конечно, чтобы говорить о функциональном анализе, мы должны знать как используются регистры и инструкции, потому что несмотря на то, что мы не находимся под отладкой и не имеем окна с регистрами со значениями в каждый момент времени, инструкции используют их и мы должны понять их, чтобы знать то, что делает программа.
Что же такое регистры и для чего они используются?
Хорошему процессору нужны помощники в его задаче по выполнению программ.
Регистры помогают ему в этом. Когда мы видем ассемблерные инструкции, мы видем, например, что они не могут сложить содержимое двух ячеек памяти напрямую. Процессор должен переместить одну из них в регистр, а затем сложить с другой ячейкой памяти. Это пример, но, конечно, у некоторых регистров есть более определенное использование. Давайте посмотрим.
32-разрядные регистры, которые используются - это: EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI и EIP . В конце курса будет часть, посвященная 64-битным.
Регистры общего назначения
EAX (Аккумулятор): Аккумулятор используется для таких инструкций как деление, умножение и некоторых инструкций формата, и также как регистр общего назначения.
EBX (База): Он может непосредственно работать с памятью, используется как база и также как регистр общего назначения.
ECX (Счетчик): ECX регистр общего назначения, который может использоваться в качестве счетчика для различных инструкций. Он также может иметь адрес смещения данных в памяти. Инструкции, которые используют счетчик, являются - цепочечные инструкции, инструкции смещения, ROR инструкции(циклические) и LOOP/LOOPD.
EDX (Данные): Это регистр общего назначения, который содержит часть результата умножения или деления. Он может также работать непосредственной с данными памяти.
EBP (Указатель на базу стека): EBP указывает на место в памяти. Почти всегда как база для аргументов и переменных функции, кроме того, он также регистр общего назначения.
EDI (Указатель на назначение): Часто, он указывает на адрес назначение результата в строковых цепочечных инструкциях. Он также регистр общего назначения.
ESI (Указатель на источник): Часто, он указывает на адрес источника в строковых цепочечных инструкциях. Как и EDI, ESI также работает как регистр общего назначения.
EIP: Указатель, который указывает на следующую инструкцию, которая будет выполнена.
ESP: Указатель, который указывает на верхушку части стека или пачку.
Подведём итог того, что я сказал.
Восемь регистров - EAX (аккумулятор), EBX (база), ECX (счетчик), EDX (данные), ESP (указатель на вершину стек), EBP (указатель на базу стека), ESI (указатель на источник данных ) и EDI(указатель на назначение данных).
Также там существуют 16-битные и 8-битные регистры , которые являются частями предыдущих регистров.
Если EAX равно 12345678
AX это последние четыре цифры (16 бит)
AH это 5-я и 6-я цифра и AL две последние цифры (8 бит каждая)
Есть 16-разрядный регистр для младшей части регистра EAX называющийся AX и два 8-разрядных регистра называющихся AH и AL. Не существует специальных регистров для старшей части .
Эти регистры существуют в той же формы для EBX (BX, BH и BL), для ECX (CX, CH и CL) и это применимо почти ко всем регистрам (только у ESP есть 16-бит SP, но не SL из 8 битов)
Здесь Вы можете видеть регистры, такие как EAX, EDX, ECX, и EBX, которые имеют регистры из 16 и 8 битов и EBP, ESI, EDI и ESP, которые имеют 16-битные подрегистры.
Мы будем рассматривать и другие регистры, один из них важный вспомогательный регистр EFLAGS, который активирует свои флаги, которые принимают значения на основе решений в разные моменты выполнения программы, которые мы рассмотрим позже, сегментные регистры указывают на другие части исполняемого файла, такие как CS=CODE, DS=DATA и т.д.
Другая важная деталь, это размеры большинства используемых типов данных.
IDA управляет большим количеством данных, которые мы будем видеть постепенно, чтобы не усложнять обучение, важная вещь состоит в том, чтобы знать, что BYTE равен 1 байту в памяти, WORD 2 байтам и DWORD составляет 4 байта.
ИНСТРУКЦИИ
IDA работает с синтаксисом инструкций, который не является самым простым в мире, большинство же людей используют дизассемблер OLLYDBG, который более прост и без кофеина (проще понять), несмотря на то, что OLLYDBG дает нам меньше информации.
Инструкции перемещения данных
MOV
MOV dest,src: Она копирует содержимое источника операнда (src) в место назначения (dest).
Операция: dest ← src
Здесь есть несколько возможностей. Например, нам может понравиться первая возможность переместить значение одного регистра в другой.
MOV EAX, EDI
В целом, мы можем перемещать из или в регистр непосредственно, принимая во внимание это EIP не может быть МЕСТОМ НАЗНАЧЕНИЯ или ИСТОЧНИКОМ в любой операции. Мы не можем сделать так
MOV EIP , EAX
Это не допустимо.
Другая возможность состоит в том, чтобы переместить константу в регистр, например.
MOV EAX, 1
Другая возможность состоит в том, чтобы переместить значение адреса памяти, а не ее содержимое (Эти инструкции в изображении принадлежат другой программе, не CRACKME.exe, потому что они не были там, но есть в VEViewer.exe, файл приложен к этой части 3)
В этом случае, когда значение будет перемещено, оно является адресом памяти, слово OFFSET, указывает нам, что мы должны использовать адрес, но не его содержание.
Или если нажмём Q , оно становится таким
MOV EAX, 46f038
Эта ещё одна инструкция как в OLLY, но она не дает нам информации о содержимом этого адреса. Если мы щелкаем правой кнопкой по адресу 46F038, мы можем вернуться к исходной инструкции.
И она станет как прежде.
Что говорит мне эта дополнительная информация? Что IDA говорит мне о вышеупомянутом адресе памяти?
Если я открываю окно HEX DUMP и поищу упомянутый выше адрес, я вижу, что первично он равен нулю. Я знаю, что это DWORD, но я действительно не знаю что это, потому что он зависит от того, где он использует это значение в программе, что определяет тип этой переменной.
Если я вернусь к списку и дважды щелкну в этом адресе.
Здесь я буду видеть, что IDA говорит мне, что содержимое вышеупомянутого адреса DWORD, в окне дизассемблера IDA, когда мы видим область памяти, которая не является кодом, поскольку в этом случае принадлежит секции данных, конечно, первая колонка это адреса.
IDA говорит мне dword_46F038, это означает, что содержимое ячейки памяти равно DWORD, это похоже на разъяснения адреса слева, здесь есть тип данных dd, который является знакомым нам DWORD и потом значение, которое содержит вышеупомянутая ячейка памяти, является нулём.
IDA говорит мне, что программа использует этот адрес как DWORD и на правой стороне я вижу ссылки, где этот DWORD будет использоваться.
Там есть две ссылки, каждая стрелка, это одна из них и подведя курсор мыши над ней я могу видеть код, также если я нажму X на этом адресе, я увижу откуда сюда ссылается программа.
Первая, где читается адрес, где мы были ранее, вторая, записывает DWORD по адресу 0x46F038, вот почему IDA в первой инструкции говорит нам, что тот адрес указывает на DWORD, потому что тут была другая ссылка, которая получает доступ к ней и записывает этот DWORD и сейчас все чисто.
Так что, IDA в первоначальной инструкции не только сообщила мне, что собирается поместить адрес в регистр, но она также сказала мне, что этот адрес содержит DWORD, это что-то вроде бонуса.
Так что, когда мы видим, что говорится о числовых адресах, IDA помечает адрес как OFFSET и когда мы будем искать его содержимое, как в этом случае, оно будет равно нулю, она не использует квадратные скобки, если это числовой адрес.
Как ранее мы видели.
mov eax, offset dword_46F908
Эта инструкция поместит адрес 0x46F908 в EAX
mov eax, dword_46F908
Эта инструкция поместит содержимое или значение, которое расположено в вышеупомянутой памяти.
Эта инструкция, которую помним по OLLY с квадратными скобками для, тех кто привык к этому отладчику.
MOV EAX,DWORD PTR DS:[46f908]
Или когда адрес имеет впереди слово OFFSET, он ссылается на этот самый адрес, а когда этого слова нет, то ссылается на значение полученное по этому адресу.
Это просто случается, когда мы обращаемся к числовым адресам, если мы работает только с регистрами.
Здесь, инструкция использует квадратные скобки, потому что, очевидно, она не знает статически какое значение содержит регистр в этот момент, и она не знает на какой адрес будет указывать, чтобы получить больше информации.
Конечно, в этом случае, если EDI указывает например на 0x10000, упомянутая выше инструкция будет искать содержимое адреса памяти и оно будет скопировано в ECX.
Очень важно понимать, что когда IDA использует слово OFFSET перед адресом памяти она ссылается на это же числовое значение, а не на его содержимое, давайте рассмотрим ещё один пример.
Тут мы видим, что в EAX помещается значение 0x45f4d0, потому что впереди есть слово OFFSET и также она говорит мне, что упомянутый выше адрес содержит stru_, который является структурой.
В другом случае, в первой помеченной инструкции, перемещается содержимое 0x46fc50, которое DWORD ,а во второй, просто адрес, который равен числу 0x46FC50.
Мы видим, что значение вышеупомянутого адреса будет помещено в 0x42f302, если мы кликнем в 0x46fc50, давайте посмотрим, что там есть.
Мы видим, что инструкция помещает ноль, если другая инструкция не выполнилась и сохранила значение, которое я изменил, поскольку она показывает нам ссылки.
С помощью нажатия на X на ссылки, мы видим все ссылки, видим, что инструкция сохраняет DWORD по адресу.
Инструкция, которая выделена желтым цветом, сохраняет DWORD в вышеупомянутый адрес памяти, все другие или читают адрес смещения или читает само значение по адресу, там где нет слова смещение.
Конечно, константы можно также поместить в 16-ные и 8-ные регистры, которые мы видели ранее.
Эта инструкция помещает 1 в AL, оставляя остальную часть EAX со значением, которое было прежде. Тут просто изменяется самый младший байт.
Здесь, инструкция перемещает содержимое адреса памяти 0x459C24 в AX и говорит нам, что это WORD.
И мы видим, что первично здесь ноль, возможно, далее при выполнении программы он может быть изменен.
Здесь AX помещается в содержимое EBX, т. к. это регистр, то не знаем какое значение имеет регистр AX, IDA не может сказать больше, она использует квадратные скобки, чтобы указать что, записывается в содержимое адреса EBX.
Здесь, инструкция запишет значение AX в содержимое ESI+8.
Другой пример
Если я щелкну на страшное имя, оно приведет меня сюда
Мы знаем, что это IAT (таблица, которая сохраняет импортированные адреса функции, когда запускается программа), она почти всегда находится в разделе idata.
Если я ищу этот адрес в окне HEX DUMP, у него всё еще нет указателя на функции, потому что IAT заполняется, когда процесс запускается, а тут он ещё не запустился.
Если я пойду в OPTIONS->DEMANGLE NAMES и выберу NAMES будет намного лучше.
Префикс EXTRN подразумевает, что это ВНЕШНЯЯ импортированная функция.
Если мы прокрутим выше, мы видим, что программа говорит, что есть импортированные функции, которые принадлежат модулю DVCORE.dll и выше есть другие, которые принадлежат различным функциям.
Мы видели различные примеры MOV, которые Вы можете практиковать и видеть в IDA , в той программе, которую я приложил к уроку.
В 4-той части, мы продолжим и разберём больше инструкций.
Автор оригинального текста — Рикардо Нарваха.
Перевод и адаптация на английский язык — IvinsonCLS.
Перевод и адаптация на русский язык — Яша Яшечкин.
Перевод специально для форума системного и низкоуровневого программирования - WASM.IN
18.02.2017