Как найти в ida pro

We covered how to search for things in choosers (list views),  but what if you need to look for something elsewhere in IDA?

Text search

When searching for textual content, the same shortcut pair (AltT to start, CtrlT to continue) works almost anywhere IDA shows text:

  • Disassembly (IDA View)
  • Hex View
  • Decompiler output (Pseudocode)
  • Output window
  • Structures and Enums windows
  • Choosers (list views)

This search matches text anywhere in the current view, for example both the instructions and comments, if present.

For the main windows, the action is also accessible via the Search > Text… menu.

The notice “(slow!)” refers to the fact that for text searching, IDA has to render all text lines in the range being searched, which can get quite slow, especially for big binaries. However, if you need the features like regexp matching, or searching for text in comments, the wait could be worth it.

Binary search

Available as the shortcut pair AltB/CtrlB, or Search > Sequence of bytes…, this feature allows searching for byte sequences (including string literals) and patterns in the database (including process memory during debugging). 

The input line accepts the following inputs:

  1. byte sequence (space-delimited): 01 02 03 04
  2. byte sequence with wildcard bytes represented by question marks:  68 ? ? ? 0 will match both  68 C4 1A 48 00 and 68 D8 1A 48 00.
  3. one or more numbers in the selected radix (hexadecimal, decimal or octal). The number will be converted to the minimal necessary number of bytes according to the current processor endianness. For example, 04469E0 will be converted to E0 69 44 on x86 (a little-endian processor). This feature is useful for finding values in data areas or embedded in instructions (immediates).
  4. Quoted string literals, for example "Error". The string will be converted to bytes using the encoding specified in the encoding selector. If “All Encodings” is selected, search will be performed using all configured encodings.
  5. Wide-character string constant (e.g. L"test"). Only UTF-16 is used convert such strings to raw bytes.

Immediate search

As mentioned previously, the same instruction operand can be represented in different ways in IDA. For example, an instruction like

test dword ptr [eax], 10000h

can be also displayed as

test dword ptr [eax], 65536

or even

test dword ptr [eax], AW_HIDE

So if you do the text search for 10000h, IDA will find the first variation but not the other two. On x86, you can use binary search for 10000 hex (will be converted to byte sequence 00 00 01), but this will not work for processors which use instruction encodings on non-byte boundary, or may give many false positives if unrelated instructions happen to match the byte sequence. So here’s why the immediate search is preferable:

  1. it only checks instructions with numerical operands or data items, improving search speed and reducing false positives;
  2. it compares the numerical value of the operand, so any change in representation does not prevent the match, meaning it will find any of the three variations above

Available as the shortcut pair AltI/CtrlI, or Search  > Immediate value…

The value can be entered in any numerical base using the C syntax (decimal, hex, octal).

Search direction

By default, all searches are performed “down” from the current position, i.e. toward increasing addresses. You can change it by checking “Search Up” in the individual search dialogs or beforehand  via Search  > Search direction. The currently set value is displayed in the menu item as well as IDA’s status bar.

The “search next” commands and shortcuts (CtrlT, CtrlB, CtrlI) also use this setting.

Find all occurrences

This checkbox allows you to get results of the search over whole database or view in a list which you can then inspect at your leisure instead of looking at every search hit one by one.

Picking the search type

This is not a definitive guide but here are some suggestions:

  1. text (e.g. prompt or error message) displayed by the program: binary search for the quoted substring (NB: this will not work if the string is not hardcoded but is in an external file or resource stream not loaded by IDA).
  2. magic constant or error code: immediate search (in some cases binary search for the value can work too).
  3. an address to which there are no apparent cross references: binary search for the address value (will only succeed if the reference actually uses the value directly without calculating it in some way).
  4. specific instruction opcode pattern: binary search for byte sequence (possibly with wildcard bytes).
  5. instruction not having a fixed encoding: text search for mnemonic and/or operands (possibly as regexp).

More info: Search submenu

0x00 start

; {EN} entry point, do nothing, just run _main {EN}

Статья для начинающих “воинов тьмы”, тех, кто хочет погрузиться в темную сторону силы: реверс-инжиниринг. На нашем “операционном столе” будет небольшой кустарный сервер, который работает по протоколу TCP/IP. Для анализа протокола обмена данными нам поможет стандарт де-факто в области реверса — IDA Pro.

Статей по реверс-инжинирингу и по IDA Pro уже написано немало (хотя и не столько, как по PHP), но поскольку процесс реверса — исследовательский, то мысли, как с «другого боку» подойти к задаче обратной разработки, полезны новичкам. По крайней мере, как автор, я руководствовался тем, чтобы изложить основные практики и техники, о которых говорю в первые дни всем стажерам и на первых парах курса по реверс-инжинирингу в университете.

Чего не будет в статье?

Поиска уязвимостей и разработки эксплоитов для Google Chrome или Apple iPhone… Поэтому если вы исследователь со стажем и с большим количеством CVE на счету, маловероятно, что вы найдете для себя что-то новое.


«Once you start down the dark path, forever will it dominate your destiny».

Подопытный: crackme — не запускайте бинари на основной системе, лучше это делать на виртуалке!

Системные требования: виртуальная машина с установленной Windows 7/0xA

0x01 mov eax, ds:__stack_chk_guard

; {EN} Disclaimer {EN}

Практически вся статья написана относительно ассемблера и, соответственно, процессора x86, поэтому работа с памятью, условными переходами (флагами), инструкциями и т.п. будет описываться в контексте именно этого процессорного ядра. На момент чтения статьи считаем, что других процессорных архитектур не существует.

0x10 Что нам нужно, чтобы понять о чём пойдет речь?

; {EN} Setups prerequisites for the consequent execution {EN}

Чтобы статья была интересна и понятна, предполагается, что читатель знает:

  • язык программирования C или C++;
  • основы языка ассемблера x86;
  • о существовании форматов исполняемых файлов (PE, ELF);
  • о кадре стека функции, поверхностно — достаточно;
  • как работать с сокетами;
  • математический анализ;
  • теорию ядерной физики.

Итак первое, что нам понадобится — сама IDA Pro от фирмы Hex-Rays (на русском произносится, как “ида про” или просто “ида”, для тех, кто любит соблюдать правила английского звучания “ай да про”, но звучит в русскоговорящей среде немного необычно). Вы можете скачать бесплатную версию для того, чтобы попробовать освоить реверс-инжиниринг, однако у неё есть ряд ограничений, среди которых: нельзя сохранять результат (в терминах IDA — базу данных) и подходит только для x86.

Второе, что нам понадобится — подопытный. Подойдет любой исполняемый файл (он же бинарник, он же файл с расширением *.exe для Windows), но рекомендуется взять тот, что прикреплен к статье. Если вы возьмёте свой бинарник, то лучше, если это будет скомпилированный для x86 файл (для первого раза не стоит брать собранные под x64 — в них ассемблер сложнее).

Третье — конечно же, хотя бы начальные знания языка ассемблера x86 (assembler language).

Чтобы осознанно копаться в программе и реверсить её, очень желательно знание языка ассемблера x86: инструкций (mov, lea, push/pop, call, jmp, арифметических и условных переходов), регистров и принципов работы процессора. Если их совсем нет, то настоятельно рекомендуется в начале изучить, например:

  • подробно, на русском: Ассемблер. Уроки 2011 (не обращайте внимание, что дизайн из 90-х);
  • кратко по ассемблеру, на английском: Guide to x86 Assembly;
  • средне, что на самом деле видит процессор, на английском: A Guide To x86 Assembly.

Может показаться, что инструкций огромное количество. На самом деле достаточно понять порядка 10 штук, остальные мало чем отличаются. Смотреть референс по инструкциям можно здесь или же в самой документации на процессорное ядро (предпочтительней).

Примечание автора. Хочу отметить, что когда сам только начинал заниматься этим, ассемблер выглядел, как сейчас продолжает выглядеть regexp (регулярные выражения) — вроде все буквы знаешь, а в слова не складываются. Однако постепенно начал понимать, что делают инструкции и что происходит в процессоре.

Четвертое — 30 минут времени (хотя, может быть, 30 часов) и желание научиться.

0x20 Минутка философии или что такое IDA Pro и почему?

; {EN} Whatta hell? {EN}

Реверс-инжиниринг (или обратное проектирование) — “это процесс извлечения знаний из того, что когда-либо было сделано человеком… Фактически, реверс-инженер — исследователь (научный работник), с той лишь разницей, что разбирается в том, что получено не естественным образом, а кем-то создано” — Reversing: Secrets of Reverse Engineering, Eldad Eilam.

Что же в первую очередь нужно исследователю? Блокнот и ручка, чтобы вести и систематизировать полученные знания. Так, а при чем тут IDA? IDA — аббревиатура, которая расшифровывается как “интерактивный дизассемблер“. Ключевым и революционным в свое время было именно “интерактивный”. Это означает, что в результате работы вы получаете не просто длиннющий ассемблерный листинг, а что-то, где вы можете оставить свои заметки, то есть как будто это действительного листинг, но в котором можно сделать “заметочки на полях”, и они меняются по ходу всего листинга. Можно еще сравнить с функцией рефакторинга в современных программерских IDE — переименовали функцию в одном месте, она переименовалась везде, переменную — аналогично и т.д. Ваша задача как исследователя — из огромного массива сложно анализируемой информации оставить только важную и придать ей форму хорошо понятную для человека. Именно интерактивность IDA Pro и позволяет делать это очень эффективно, и на сегодняшний день никто её в этом не превосходит.

Стоит все же заметить, что с учетом постоянно возрастающей закрытой кодовой базы и напечатанного мартышками кода в интернете, программное обеспечение реверсить вручную и интерактивно становится все сложнее и сложнее. Из-за этого сейчас активно развиваются средства анализа кода, нацеленные на автоматизированную обработку — radare2 (что бы ни говорили адепты r2, интерактивный интерфейс Cutter не настолько интерактивен, как в IDA Pro). Более того, IDA Pro также очень хорошо автоматизирована с помощью встроенного в неё интерпретатора Python и API к нему.

И все-таки, как бы крут не был автоматизированный анализ, он не автоматический, то есть заменить на все 100% исследователя не может и рано или поздно исследователю нужно вступать в бой. Поэтому, когда все приготовления наконец-то закончены, приступаем к изучению IDA Pro! Начнём постепенно разбирать наш подопытный образец.

0x30 Смотрим на IDA Pro и познаем основы её интерфейса

; {EN}
; This function is too complex.
; Perhaps it interacts with user.
; But currently I am not sure about it.
; A lot of calls to Qt-framework.
; {EN}

0x31 Загрузка бинарника в IDA Pro

Открываем IDA Pro. Перед нами после всех стартовых окошек (которые можно сразу же закрыть), появляется начальное окно программы. Все, что нужно сделать, — перетащить в него исследуемый бинарник. После этого в появившемся окне нажать кнопку “ОК”.


Главное окно IDA Pro при загрузке бинарника

В нашем случае (если вы грузили тот самый exe-файл в IDA, который приложен к статье) никаких настроек производить не нужно, IDA Pro сама распознает формат этого файла (PE, portable execute), а вот если туда кинуть прошивку или дамп из микросхемы памяти от, например, роутера, всё будет намного сложнее.

Какого-то единого стандарта хранения прошивки, можно сказать, нет. Каждый производитель сам для себя выбирает формат файла обновления, что даёт некоторую защиту от реверс-инжиниринга, так как, чтобы докопаться до кода, приходится сначала разобрать этот формат.

После извлечения из файла обновления, код сам по себе может быть размещен по какому угодно адресу в памяти устройства. Найти точку базирования кода — отдельная задача, заслуживающая своей статьи.

Что же касается дампа памяти, то на самой микросхеме может уже находится файловая система с учетом “скрамблинга” (перемешивания блоков на флеш-памяти с целью уменьшения износа). Собрать обратно эти блоки часто является не самой тривиальной задачей. Чтобы восстановить схему скрамблинга, необходимо реверсить сам скрамблер.

Скрамблер в студию

Знакомьтесь, так выглядит типичный алгоритм скрамблера (см. ниже). Причем на рисунке показана только “внешняя” функция, а в каждом из блоков может быть вызов еще такой же или чего-нибудь пострашнее.


Так выглядит граф потока выполнения скрамблера

0x32 Что нам IDA Pro показала?

После загрузки бинарника IDA Pro проводит его предварительный автоматический анализ: определяет функции, глобальные переменные, строки — всё, что можно автоматически вытащить из анализируемого файла. Анализ выполняется процессорным модулем IDA Pro (не путать с самим процессором). Фактически это плагин для IDA Pro (при желании можно написать свой на Python или C++). В нашем случае IDA использует так называемый Meta PC — вариант x86/x64, учитывающий большинство твиков, которые были добавлены в архитектуру от Intel и AMD. Автоматический анализ выполняется опять же на основе того, что есть полное описание формата файла, который мы загрузили в IDA, в нашем случае тот самый Portable Executable. Данный формат чётко указывает какие секции есть в файле, в какой из секций лежит код, где его точка входа, а в какой секции данные (константы или глобальные переменные). Как обычно, с прошивками такой финт не проходит и необходимо вручную размечать входной файл (или же писать loader-плагин для IDA, который сможет «рассовать» куски бинарника прошивки как нужно, после чего процессорный модуль IDA сможет приступить к анализу).

Автоматический анализ под капотом крайне сложная штука, но для каждой инструкции он состоит в следующем:

  • декодирование инструкции из бинарного представления во внутреннее (analyze);
  • связывание инструкции с учётом специфики её выполнения (emulate — не путать с эмуляцией, как, например, в QEMU);
  • преобразование инструкции и аргументов в мнемонику.

Поверх этого с учётом информации и “связей” между инструкциями IDA выбирает путь для анализа следующего адреса, выполняя условный обход “дерева” инструкций от начальной точки анализа. За счёт того, что в стандартных форматах десктопных программ точка входа всегда известна (иначе загрузчик ОС не смог бы создать процесс из этого файла), IDA также может использовать эту информацию.

Следует отметить, что это очень общее описание того, что происходит на самом деле. Приведено оно с той целью, чтобы дать базовое понимание, что такое автоматический анализ, выполняемый в IDA.

Пару слов о том, как IDA Pro хранит результат реверса. После или во время автоматического анализа “проект” можно сохранить (если, конечно, у вас полная версия). IDA хранит результат анализа в виде специальной базы данных со своей структурой (нет, это не модная MongoDB) на жёстком диске. Она представляет собой один файл с расширением .idb (или .i64).

После того как автоматический анализ завершён, вы увидите окно, примерно такое, как на рисунке ниже. Основные элементы, на которые стоит обратить внимание начинающему исследователю, подписаны на самом скриншоте. Завершение автоматического анализа можно определить по надписе AU: Idle в левом нижнем углу IDA Pro.

UX/UI IDA Pro

GUI IDA Pro написан на Qt, поэтому, если вы когда-нибудь работали с приложениями, написанными на Qt, тут действуют те же самые правила:

  • тотальный drag&drop окошек;
  • все открывается в разных вкладках, которые можно переставлять как вам угодно. Иногда их можно случайно закрывать и потом долго искать меню, где открывается эта вкладка.


Граф потока выполнения функции main

Давайте рассмотрим основные окна, которые первоначально отображает нам IDA Pro.

  • Граф потока выполнения — основной вид дизассемблера (можно сказать, представление в виде блок-схемы алгоритма функции). В нем отображаются инструкции процессора, полученные после дизассемблирования из бинарного вида. В этом графе показывается только одна функция. Каждая функция может быть разделена на блоки по инструкциям условного или безусловного перехода (пошли направо — один блок, налево — другой блок). Кроме этого вида есть и другой, где результат дизассемблирования отображается в виде сплошного листинга.

Proximity View

Есть и еще один вид, который называется Proximity View. Он отображает взаимосвязь между функциями и глобальными переменными.

Примечание автора. На мой взгляд, представление в виде графа более удобно, так как дает представление о структуре функции.

  • Список функций — окно, в котором выводятся функции, которые нашлись в бинарнике. Это те самые функции, которые были написаны программистом при создании программы (не учитывая оптимизацию). Если разработчик при компиляции не убрал отладочную информацию (в gcc это опция -s) или вообще собрал программу с опцией -g, тогда мы увидим все имена функций точно в таком же виде, как и программист. Иначе IDA Pro отобразит их в виде sub_<виртуальный_адрес _функции>;
  • Список строк (Strings) — не показан, но можно построить, нажав на SHIFT+F12. Одна из самых важных менюшек IDA Pro — в ней показаны все строки, которые есть в программе. Используя строки можно в некоторых случаях, найти всю интересующую нас функциональность.

0x33 Трогаем “лапой” IDA Pro

Наконец-то открыли бинарник и увидели, как это выглядит изнутри. Что же с ним делать и с чего начать реверс? С чего начать трогание нашего основного инструмента в реверсе, IDA Pro? Первое — виртуозное владение пианино горячими клавишами. Без знания горячих клавиш жизнь реверс-инженера скучна, так как сочетания клавиш сильно помогают её разнообразить и очень поднять эффективность и скорость реверса.

Когда только учишься работать в IDA Pro лучше постоянно держать перед глазами табличку (чит-шит, cheatsheet) с горячими клавишами. Ниже приведен пример моего чит-шита. Есть и официальный чит-шит от самой фирмы разработчика IDA Pro — Hexrays. Официальный чит-шит можно найти здесь, в нем больше сочетаний кнопок, но, на мой взгляд, на первое время будет достаточно того, что приведено на чит-шите ниже.

Где CTRL+S и CTRL+Z?

Внимательный читатель может заметить, что в этой таблице нет двух важных сочетаний клавиш. Первое — сохранение базы данных результатов реверса (CTRL+W, но в бесплатной версии сохранения нет), второе — undo. Так вот, забудьте про undo — его нет. Настоящие реверс-инженеры слишком суровы, чтобы использовать всем привычный CTRL+Z. Если серьезно, то функцию undo завезли только в версии 7.3 (бесплатная — 7.0), а всё потому что выполнить undo — не очень тривиальная задача. Дело в том, что какое-то изменение в базе данных IDA, внесенное пользователем, может привести к последующим множественным лавинным изменениям. Например, создание функции (make code) ведет к рекурсивному созданию всех вызываемых функций.

После того, как ознакомитесь с табличкой горячих кнопок, рекомендую попробовать некоторое время понажимать их в самой IDA Pro. При этом не стоит бояться, что вы что-то сломаете или перейдете «не туда», потому что именно так и будет. Как и любую сложную систему, освоить IDA Pro до виртуозного владения за один вечер невозможно.

Пройдемся и заодно опробуем различные кнопки в IDA Pro.

0x33a Навигация по графу и листингу

Навигация — одна из самых простых и понятных задач, однако, чтобы не теряться в IDA Pro, следует потренироваться в следующем:

  • перемещения по графу функции с помощью мыши;
  • перейти на различные функции с помощью двойного нажатия мыши, вернуться обратно с помощью ESC и снова вперед с помощью CTRL+ENTER (нет в чит-шите — для продвинутых);
  • переключения между графом и листингом — SPACE, если вдруг у вас включился другой вид (листинга);
  • переход по перекрестным ссылкам: поставить указатель мыши на любое имя (функции или переменной) и нажать X. После этого вы увидите окно с другими инструкциями, которые ссылаются на это имя (или же указатель в памяти программы);
  • прямой переход на имя или адрес (g): в открывшемся окне написать любое из существующих имен или же адрес (можно без 0x) из текущей база данных IDA Pro — вы перейдете на ту часть графа (листинга), где определено это имя.

0x33b Именование и заметки на полях

По изменению имен (рефакторингу) следует попробовать и отработать следующие действия:

  • Переименование имен (для этого необходимо нажать мышью на имя и после этого N): функций, переменных (локальных и глобальных), регистров и меток. Постарайтесь разобраться, что можно переименовать, а что нет.
  • Простановка комментариев к инструкциям. В целом все просто: выбрали строку, к которой хотим поставить комментарий, и нажали ;.

0x33c Представление данных (data representation)

Любую часть анализируемого бинарника можно представить в виде различных вариантов:

  • байт (byte);
  • слово (word);
  • двойное слово (dword);
  • указатель (offset);
  • неопределенное (undefined);
  • дизассемблированный код (code).

Иначе говоря, каждый адрес в бинарнике можно попытаться дизассемблировать, если получится — будет код, иначе просто данные (байт, слово и т.д.). По умолчанию, если не проводить никакого анализа (в том числе и автоматического), весь бинарник представляется IDA Pro как undefined. Можно сказать, что в процессе реверса или автоматического анализа происходит разметка того, как представить каждый из байтов загруженного бинарника. То, что мы с вами видим уже размеченным (причем практически все байт), является результатом автоматического анализа, который выполнила IDA Pro.

0x33d Отличие кода от функции

Отдельно можно отметить и представление кода:

  • Код без функции (в таком случае IDA Pro не сможет построить граф);
  • Функция (чтобы из кода создать функцию, необходимо нажать P).
    Для большей части кода во время автоматического анализа IDA Pro сама распознает, где необходимо создать функции. Каким образом? За счет того, что если во время дизассемблирования встречается инструкция вызова (call), то анализатор однозначно может утверждать, что адрес, находящийся у этой инструкции в аргументе, — адрес начала функции.

Раз здесь спойлер, значит не все так просто

В реальности за счет использования различных техник защиты от реверса или просто из-за того, что мы грузим в IDA Pro прошивку и не знаем, где в ней начало кода, IDA Pro может начать дизассемблирование не с того адреса. Это приведет к тому, что будет получена инструкция call, хотя ее там и нет, а адрес «псевдоинструкции» call также не является началом никакой функции. Кроме того, какие-то данные, необходимые для работы программы, могут быть декодированы, как инструкции вызова — результат аналогичный.

0x33e Представление аргументов инструкций

Кроме представления каждого байта в виде различных вариантов указанных выше, можно по разному представить и аргументы большинства инструкций. Например, в инструкции записи числа в регистр mov eax, 0xFFFFFFFF второй аргумент может быть представлен, как в текущей записи, так и mov eax, -1. Для того, чтобы сменить вариант представления аргумента инструкции, необходимо нажать на него правой кнопкой мыши, и IDA Pro покажет возможные варианты представления.

0x33f Вспомогательные окна IDA Pro

В первую очередь стоит обратить внимание на Strings, Names, Functions, Hex Dump. Все эти окна можно открыть перейдя из строки меню View->Open Subviews.

0x40 Всего так много и как с этим работать?

; {EN}
; I think I found actual protocol parsing in function sub_401D3C
;
; But this function just chases bytes from corner to corner
; before actual parsing... we need to go deeper
; {EN}

0x41 Что же мы будем делать?

Теперь, когда мы знаем на какие кнопки надо нажимать и приблизительно представляем как «под капотом» работает IDA Pro, давайте попробуем вернуться к нашей задаче и найти ту часть бинарника, которая отвечает за разбор протокола обмена данными подопытного сервера.

Если внимательно посмотреть на вкладку с перечнем функций, можно увидеть, что IDA нашла в нём всего лишь 76 функций, то есть это очень маленькая программа. Реальные программы и, тем более прошивки, могут состоять из сотни тысяч функций. При этом никогда не ставится задача «втупую» восстановить исходный код программы на 100% (по крайней мере в моей практике никогда такого не было). Среди прочего от реверса бывает нужно:

  • Найти в протоколе ошибки. Для этого в программе необходимо искать места, связанные с получением данных извне;
  • Разобрать некий протокол взаимодействия, чтобы, например, создать свой API;
  • Пофиксить баг в чужой неподдерживаемой программной библиотеке (серьёзно, такое приходилось делать пару раз);
  • Что-то ещё…

Таким образом, главная задача, которая стоит перед исследователем, — найти некоторые интересующие места программы. Иначе говоря, реверсить всё целиком зачастую не имеет смысла, да и процесс этот слишком трудоёмкий. Не стоит забывать, что обратный анализ кода занимает времени больше, чем его прямая разработка.

0x42 Иголка в стоге байт

; {RU}
; Ищем функцию получения данных извне;
; Ищем на неё ссылки;
; Если не нашли, пытаемся искать по логам (повторяем пп.1-3);
; {RU}

Как же найти иголку в стоге сена? На самом деле, подходы практически такие же, как когда знакомишься с новым API или OpenSource-проектом, а вся документация в нем сделана в «doxygen»: пытаемся искать функции с вменяемыми именами или идём от API операционной системы.

Что не так с doxygen?

Наличие документации в doxygen — это отлично. Подразумевается, что это единственная документация, причем во время разработки программисты не всегда удосуживались написать комментарии к функции. То есть, все, что есть, — это HTML представление кода с именами функций и параметров (крайний случай).

Поскольку исходно сказано, что это TCP/IP-сервер, логично предположить, что данные будут “приезжать” в обработчик через recv, хотя в реальности могут быть использованы и другие функции. Например, recvfrom, или API более низкого уровня — самой ОСи (для Linux — read).

Заметка: кто хочет вспомнить/познакомиться с работой с сокетами в Си, тот читает Socket programming in c using TCP/IP.

Как сделать это в IDA Pro? Сначала нам нужен перечень всех имен (строк и имен функций, вкомпилированных в программу и импортируемых из библиотек). Для этого служит сочетание клавиш SHIFT+F4. После нажатия откроется вкладка с именами (Names).

На вкладке с именами можно воспользоваться поиском, точнее фильтром (в широком смысле, это более сложная функция с возможностью фильтрации строчек с помощью регекс выражения). Для того, чтобы вызвать поиск, необходимо, находясь во вкладке с именами, нажать сочетание клавиш CTRL+F. После этого внизу вкладки откроется строка ввода (как показано на рисунке). В эту строку необходимо написать часть слова, которое мы хотим найти (в нашем случае это будет recv), список сократится, и в нем останутся только те строки, в которых встречается заданное ключевое слово (на рисунке не показано).

Во второй колонке выводится адрес соответствующего имени. Для перехода на этот адрес в листинге следует дважды кликнуть по нему (или ENTER).

Заметка: переход назад в листинге выполняется по горячей клавише ESC.


Окно имен данного бинарника

И вот мы попадаем обратно в листинг. Теперь уже по адресу функции recv (вспоминаем, что recv в данном случае — библиотечная функция, и её код находится в динамической библиотеке).

Следующим шагом необходимо найти те места в программе, в которых происходит вызов функции recv. Для этого во время анализа IDA Pro создает перекрёстные ссылки между инструкцией вызова функции (или другим обращением к функции) и самой функцией. Чтобы посмотреть места, где используется функция, необходимо навести мышку на адрес (или имя), к которому мы хотим найти перекрёстные ссылки, и нажать кнопку X. Вслед за этим откроется окно, как на рисунке ниже. В окне будут перечислены все найденные перекрестные ссылки. Причем в колонке type используется следующая нотация:

  • p[rocedure] — перекрёстная ссылка “по вызову”, то есть адрес (имя) используется в инструкции call;
  • r[ead] — перекрёстная ссылка на чтение; в этом месте программы происходит чтение из данного адреса (имени);
  • w[rite] — перекрёстная ссылка на запись; в этом месте программы происходит запись в данный адрес (имя).

В нашем случае ссылок всего две:

  1. Чтение адреса функции recv в регистр (тип r),
  2. Непосредственный вызов recv (тип p).
    Можно заметить, что реально прямой перекрёстной ссылки на recv в инструкции вызова нет. Листинг вызова выглядит следующим образом:

push    0
push    1000h   ; len
push    ebx     ; buf
push    edi     ; s
call    esi     ; recv   <----  Вызов recv здесь

Как видно из кода ассемблера, инструкция call выполняет переход по адресу из регистра esi. Во время автоматического анализа IDA отслеживает, какое значение было занесено в регистр esi, и делает вывод, что при выполнении call в регистре esi всегда будет адрес recv. Именно поэтому IDA создает перекрёстную ссылку на recv в этом адресе.


Перекрестные ссылки на recv

Выбираем из списка ссылку с типом p, и IDA перекидывает нас в граф (или листинг), где происходит вызов функции recv. Выше на экране — листинг IDA. Мы можем увидеть функцию, вызывающую recv: sub_401D3C.

Просто? Да. В данном случае. В реальности же может оказаться, что прямых ссылок нет, а вместо recv вызываются другие функции, или же данные сохраняются в какой-то буфер в структуре, и потом обрабатываются неизвестно где (но анализ всего этого — отдельная статья).

0x43 Делаем “заметки на полях”: sub_401D3C

; {EN} x_vserv_protocol {EN}

Что такое x_?

В нашей команде принято использовать префикс x_ для именования функций (от слова eXecutable), чтобы отличить поименованные вручную функции от автоматически поименнованных IDA Pro.
ax_ — префикс поименнованых функций скриптами (IDAPython);
v_ — префикс глобальных переменных (от слова Variable);
av_ — аналогично, но поименнованных скриптом (IDAPython).

Функция sub_401D3C в отличие от recv является частью данной программы. Поэтому можно исследовать, что происходит в этой части «подопытного».

Заметка: вообще исследование программы часто делится на два основных метода: статический и динамический анализ. Статика подразумевает, что весь анализ выполняется только на основе кода (без запуска программы), динамика — с учётом информации получаемой в дебаге.

В нашем случае проще было бы запустить подопытного в дебаге (англ. «debug» — отладка) и уже после этого начать изучать, что с ним происходит. Но, во-первых, чтобы поучиться мы проведем исследование чисто статикой: где-и-что делается в обработке сразу после получения данных из сокета. Во-вторых, прежде чем что-то запускать даже на виртуалке, я предпочитаю понять, чем это может закончиться

Ну и, как говорит теория эксперимента, прежде чем выполнять сам опыт, необходимо понимать, чем он может закончиться, и на что вообще надо будет смотреть во время фейерверка. Так и в нашем случае, прежде чем запустить программу, необходимо разобраться, в каких переменных ожидать какие данные, а всё то, что сложно понять сходу, добирать с помощью информации, полученной из динамики.


Место вызова функции recv

Начнем делать “заметки на полях”. Если окинуть взором функцию sub_401D3C, в которой мы очутились, можно увидеть в ней вызовы двух функций с неизвестными именами: sub_401CF0 и sub_401BFD. Кроме этого, мы видим и вызов функции puts — стандартная библиотечная функция из libc. Она выводит строку в стандартный поток вывода (stdout). Раз функция что-то печатает на экран, значит, должны быть и строки, из которых можно получить какую-то информацию!

Заметка: в предыдущем разделе мы нашли интересующую нас функцию по библиотечной функции recv. Однако “золотой жилой” являются строки. Просто пробежавшись взглядом по строкам в окне Strings (SHIFT+F12) или поискав в нём различные ключевые слова, можно извлечь очень много дополнительной информации о работе программы или же найти места, в которых происходит что-то интересное для нас как для реверс-инженеров. Никогда не пренебрегайте возможностью посмотреть на строки, которые остались в программе.

Даже не особо разбираясь в ассемблере, можно легко понять, что выводит конкретно здесь puts. В блоке по адресу 0x00401D64 (чтобы перейти в этот блок, нужно нажать кнопку g и вставить в окно указанный адрес) будет выведена строка “Received failed», в блоке по адресу 0x00401D7A — «Client disconnected», а в блоке 0x00401D9C — “VSERV protocol error…”. На основании этих строк можно сделать вывод, что данный сервер имеет внутреннее название VSERV (далее при именовании функций будем использовать такой идентификатор). Кроме этого нужно поименовать метки блоков по адресам:

  • 0x00401D76 как RECV_SUCCESS;
  • 0x00401D8C как CLIENT_NOT_DISCONNECTED.

Заметка: надо стараться именовать всё во время реверс-инжиниринга. Если вы натыкаетесь на функцию и у вас есть хотя бы малейшее предположение, что делает эта функция, — переименовывайте её. В будущем, когда натыкаетесь на эту же функцию, но при других обстоятельствах, вы будете помнить, что уже имели дело с ней, и она где-то была важна для вас. Также можете провести анализ её использования по нескольким случаям применения. Дальше по тексту уже не будет приводиться фраза: “надо переименовать”, предполагается, что это рефлекс.

Далее видно, что адрес 0x00401D54 — начало цикла, в котором сервер постоянно “крутится” и получает данные от клиента. Этот адрес можно назвать “RECV_LOOP”. Цикл в IDA Pro легко найти с помощью графового представления: стрелка перехода от нижнего блока (окончание цикла) к верхнему (начало цикла) выделяется жирным.

Хорошим вариантом для имени функции по адресу 0x00401D3C, в которой мы находимся, является, например, x_vserv_protocol. Видно, что в ней происходит приём данных от клиента, после чего вызываются две функции — в них будет либо полный разбор протокола, либо же предразбор (преобразование потока данных из TCP в “сообщения”). Из кода, который есть в функции x_vserv_protocol, невозможно сделать полноценный вывод, что же происходит внутри функций sub_401CF0 и sub_401BFD, поэтому давайте зайдем поочередно в каждую из них и попробуем понять их функциональное назначение (вернуться назад можно кнопкой ESC).


Не забываем переименовывать метки и имена функций

0x44 Делаем “заметки на полях”: sub_401CF0

; {EN} x_vserv_parse_header {EN}

Начнем, пожалуй, с sub_401CF0, так как она идёт первая по ходу выполнения. Чтобы перейти в функцию, необходимо дважды нажать на неё мышью, в результате чего мы оказываемся в очень маленькой функции sub_401CF0. Граф её потока выполнения приведён на рисунке ниже. Судя только по общему виду графа (не вдаваясь в подробности ассемблера), сразу можно сделать вывод, что эта функция:

  • На вход получает только один аргумент (причем, скорее всего, с помощью функции recv данные из TCP-сокета);
  • Не имеет циклов и содержит одно ветвление (if-else);
  • Вызывает две библиотечные функции memcmp и atoi;
  • В одной из веток возвращается 0xFFFFFFFF (-1) в качестве результата;
  • Проверяет сигнатуру в пришедших данных.


_Реверс функции sub_401CF0 она же x_vserv_parse_header_

Разберёмся по порядку, откуда что взялось.

0x44a Один аргумент и его назначение в функции sub_401CF0

Аргументы IDA пытается распознать сама (для этого она, точнее её конкретный процессорный модуль, использует знание о calling convention (соглашение о вызовах) и другие методы эвристики, но может ошибаться). Если аргумент передается через стек, а не через регистр (для x86 при соглашении о вызовах cdecl, которое используется чаще всего, это именно так), то такие смещения в стеке IDA Pro сама именует с префиксом arg_.

Заметка: передача аргументов и возврат значения из функции при компиляции целиком и полностью определяются соглашением о вызове функции (calling convention). В соглашении много нюансов, и самих вариантов соглашений довольно много (какой из них используется, определяется в том числе и компилятором). Основное, что нам сейчас нужно знать, — x86-аргументы передаются через стек (с помощью инструкции push), а возвращаемое значение через регистр eax (то, что на Си пишется после return).

Назначение аргумента. Почему на скриншоте агрумент уже назван packet_buffer? Разобраться с этим можно, взглянув на предыдущую функцию, а точнее на то, что ей передается в качестве аргумента. Для разъяснений ниже приведён еще один скриншот из функции x_vserv_protocol. Аргументом в функцию приходит значение из регистра ebx. Если нажать на ebx мышкой, IDA подсветит все его использования, за счёт чего можно легко найти предыдущее применение этого значения. Оно же передается в функцию recv (да, в ту самую) вторым аргументом (вспоминаем, что согласно соглашению о вызовах в стек аргументы в коде заносятся в «обратном порядке»).


_Аргументы функции x_vserv_parse_header_

Следующим шагом (для тех, кто забыл определение функции recv) необходимо заглянуть в документацию на recv. Из неё станет понятно, что второй аргумент — адрес буфера, в который recv запишет принятые данные. Думаю, теперь очевидно, что единственный аргумент функции sub_401CF0 и есть адрес буфера с принятыми из TCP-сокета данными.

0x44b Функция sub_401CF0 не имеет циклов и содержит одно ветвление

Вспоминаем, как в IDA Pro быстро понять, есть ли в функции циклы или нет (стрелка от нижнего блока к верхнему). Аналогично смотрим на граф функции sub_401CF0 и делаем вывод, что в sub_401CF0 циклов нет.

Наверное, уже все догадались, что две выходящие стрелочки из блока в графе IDA Pro означают, что данный блок программы является частью if-else в исходном коде. Цвет стрелки означает следующее:

  • Красный — путь выполнения программы, если переход не выполняется;
  • Зеленый — если выполняется.

Выполнение перехода, в свою очередь, зависит от предыдущей инструкции. В анализируемой функции sub_401CF0 такое ветвление только одно, и чуть позже мы разберёмся, что же проверялось в исходном коде.

Заметка: обычно конструкция if-else после компиляции превращается в две инструкции (как минимум):

  1. Сравнение значений (эта инструкция выставит флаги процессора);
  2. Условный переход на основании выставленных флагов.

0x44c Функция sub_401CF0 вызывает две библиотечные memcmp и atoi

Если мы не помним определение и функциональное назначение библиотечных функций, их необходимо загуглить, так как эта информация позволит нам понять, что делает анализируемый код. Иногда названия API-функций могут быть совсем не очевидны и даже если считаете, что хорошо знаете ту или иную функцию, но возникла тень сомнения, лучше сразу посмотреть документацию, в данном случае на memcmp.

Примечание автора: иногда “fear … leads to suffering”, давным-давно, в одной забытой Галактике, я реверсил устройство и, находясь в режиме отладки при загрузке Линукса, наткнулся на вызов функции reboot. В тот момент, когда выполнение повернуло в ветку с этой функцией, я остановил отладку и начал разбираться, в чём проблема. На все разборки ушёл практически весь рабочий день. Под конец заглянув в документацию на reboot, я прочитал следующее: «or enables/disables the reboot keystroke». Победив «страх» и нажав на F8, находясь на функции reboot, я понял, что устройство не перезагрузилось, а продолжило выполняться… RTFM!

Довольно легко можно найти, что memcmp сравнивает два массива в памяти и на вход принимает указатели этих массивов и количество байт, которое необходимо «подвергнуть» сравнению. Вроде всё просто и понятно, а вот с возвращаемым значением не всё так очевидно, и новички в Си часто делают ошибку. Предполагают, что 0 — строки неравны, а 1 — строки равны. В реальности в случае равенства строк функция вернет 0, а если строки неравны, то либо > 0, либо < 0.

Вторая API-функция atoi преобразовывает число, записанное в ascii-строке, в integer. Соответственно, на вход приходит указатель на строку, а на выходе — целочисленное значение.

0x44d Собираем всё вместе и отвечаем на два оставшихся вопроса

Какие выводы можно сделать из анализа использования этих двух API-функций в исследуемой функции?

Во-первых, memcmp проверяет сигнатуру протокола (уникальную последовательность байт, чтобы «удостовериться», что пакет реально относится к заданному протоколу). Этот вывод можно сделать на основе того, что в функцию memcmp передается напрямую буфер с принятыми данными (постарайтесь отследить это сами), константная строка «VMES» и значение 4 (очевидно длина VMES). После этого, если сигнатура не нашлась, программа может повернуть в ветку, где в регистр eax заносится значение 0xFFFFFFFF (-1), или в ветку с atoi.

В данной случае используется функция memcmp, а не strcmp, хотя и сравниваются две строки, из-за того, что необходимо указать максимальную длину сигнатуры, 4 байта. Функция strcmp будет сравнивать до тех пор пока не встретит нуль-терминатор. Хотя у сигнатуры «VMES» нуль-терминатор идет последним, пятым символом, в пришедшем пакете — нуль-терминатор может быть где угодно. Из-за этого, даже если в пакете в начале будет эта сигнатура, strcmp определит эти строки как различающиеся.

Во-вторых, atoi, скорее всего, получает длину тела-сообщения (хотя напрямую это не следует из анализа только этой части кода). Взгляните внимательно и вы увидите, что atoi берёт из полученных данных кусок буфера — четыре байта следом за VMES (это можно понять, если разобрать ассемблер в блоке по адресу 0x00401D19) — и преобразует его в число. Результат преобразования atoi передается в eax. Таким образом, в eax на выходе из функции оказывается либо значение, полученное из принятых данных, либо -1. Также вспомним, что согласно соглашению о вызовах для x86 результат возврата функции находится в регистре eax, функция проверяет наличие сигнатуры в первых четырех байтах, если этих байтов в буфере нет — возвращает -1, иначе преобразует следующие четыре байта в число и возвращает его из функции. Что может быть лучше, чем описать код на естественном языке? Правильно, написать сам код:

char tmp[5] = { 0 };
if (memcmp(&buf[0], "VMES", 4) != 0)
    return -1;
*(int*) tmp = *(int*)(&buf[4]);
return atoi(tmp);

По началу код может показаться странным. Могут возникнуть такие вопросы, как: откуда буфер на 5 байт? Зачем он вообще здесь? Почему просто нельзя передать в atoi(buf + 4)? Начнем разбираться с последнего вопроса и для этого нам понадобится документация на atoi, а точнее на документация на strtol (если открыть доку на atoi, то она ссылается на strtol с указанием системы счисления 10). В ней сказано, что конвертация происходит, пока не будет встречен символ, который не подходит для данной системы счисления. То есть, для 10-ой системы это любой символ не из диапазона от 0 до 9. В ходе реверса в таких случаях, можно предположить, что автор программы хотел защититься от того, что в сервер могли отправить специально подобранный пакет, где это значение будет указано каким-угодно большим. Однако при этом (как увидим дальше) допустил другие ошибки. По итогу: копирование в отдельный буфер с нуль-терминатором позволит избежать проблемы неправильной конвертации ascii-строки.

Размер буфера в 5 байт можно определить, если заглянуть в стек программы (о котором подробнее чуть позже в статье): в списке переменных функции сразу за buffer_length идет переменная var_D (поэтому в стеке они распологаются друг за другом). В нее заносится 0 в самом начале функции, и больше эта переменная никак не изменяется. Поэтому var_D и есть нуль-терминатор.

На основании анализа предлагается дать функции гордое название x_vserv_parse_header (на скриншотах уже была переименована).

0x45 Делаем “заметки на полях”: sub_401BFD

; {EN} x_vserv_parse_body {EN}

0x45a Немного о стеке и его кадре

Итак, мы дошли до последней неразобранной функции, чтобы целиком охватить «архитектуру» той части программы, которая отвечает за обработку протокола. Как и на предыдущем этапе реверса, начать следует с её аргументов. Обратимся к блоку функции x_vserv_protocol, который мы ранее поименовали как PARSE_BODY (для этого, как обычно, можно нажать g, вставить туда название блока и нажать ENTER). Перед вызовом самой функции видны две инструкции push, которые, очевидно, передают аргументы в нужную нам функцию sub_401BFD (на скринах она уже переименована в x_vserv_protocol_body). С этой целью взглянем на рисунок, приведенный ниже.


_Что за body_buffer?_

Первым аргументом передается адрес (так как используется инструкция lea) некой переменной (на скриншоте названа body_buffer). Вторым аргументом — то, что было получено из функции x_vserv_protocol_header (так как регистр eax передается в инструкцию push без изменений). Если со вторым аргументом все очевидно — число после atoi-преобразования, то с первым давайте разберёмся.

Чтобы понять, что такое body_buffer, следует обратить внимание на пару моментов:

  • Каким образом получен указатель на буфер, который передается в recv;
  • Структура стека функции x_vserv_protocol.

Указатель на буфер, передаваемый в recv, формируется довольно очевидно. Он передается вторым аргументом в recv и, следовательно, адрес буфера находится в регистре ebx перед вызовом функции recv (см. блок RECV_LOOP). Если нажать на ebx и отследить, какое значение заносится в него перед этим, то видно, что туда перекладывают регистр esp. Регистр esp является крайне важным (хотя все регистры важны) тем, что он всегда указывает на вершину стека и, кроме этого, неразрывно связан с push/pop. Конкретно в этом случае в esp хранится начало стекового буфера, что в исходном коде выглядело как:

char buffer[0x1000];

Заметка: почему так? Чтобы ответить, нужно разобраться с тем, что такое кадр стека, и как разложены локальные переменные, а также аргументы в стеке. Подробно тому, как располагаются данные в стеке лучше почитать по одной из ссылок в начале статьи, так как тема кадра стека сама по себе заслуживает отдельной статьи. Также можно почитать статью на Wikipedia.

Рассмотрим структуру стека (кадра или фрейма) функции x_vserv_protocol. Для отображения кадра стека в IDA Pro необходимо два раза нажать мышкой на одну из переменных, расположенных в стеке (на скриншотах — «рыжие» имена в самом начале функции). После этого вы увидите картинку, похожую на рисунок ниже.


Стековый кадр функции

Как было написано выше, указатель для приема данных через recv соответствует самому началу кадру стека (так как esp используется без смещения). В связи с этим можно поименовать (как обычно — кнопочкой N) верхушку как vmes_sign (в первых четырех байтах ожидается сигнатура «VMES»).

Следующие четыре байта — это байты, которые передаются в atoi в функции x_vserv_parse_header. Вывод о группе в четыре байта, можно сделать из первой инструкции левого блока функции x_vserv_parse_header (адрес 0x00401D19). Инструкция mov перекладывает именно четыре байта из [ebx+4] в регистр eax для последующего преобразования в atoi. Поскольку мы решили, что это длина тела пакета, поименуем их как vmes_body_len.

Теперь становится понятно, что после восьми описанных байт идут оставшиеся данные из TCP-пакета. Если вы разрабатывали клиент-серверное приложение, то очевидно, что эти оставшиеся данные — тело пакета, и его парсинг (разбор), скорее всего, будет в функции, вызываемой следом за x_vserv_parse_header. Собственно, эта функция на скриншотах практически сразу и была названа как x_vserv_parse_body.

0x45b Разбираем функцию разбора тела пакета

Вернёмся обратно в саму функцию (кнопка ESC) и соберём всё вместе. Первый аргумент для функции sub_401BFD (x_vserv_protocol_body — уже можно переименовать) — тело пакета, данные, пришедшие из TCP-сокета с помощью recv, за исключением первых восьми (судя по всему, первые восемь — заголовок пакета). Второй аргумент – данные, находящиеся по смещению +4 от начала пакета (предположительно, длина тела пакета) и «пропущенные» через atoi, чтобы получить из них число.

Заметка: если кто-то со знанием Stack BOF (он же Stack Buffer Overflow, оно же переполнение буфера в стеке) решил почитать статью, он наверняка уже учуял запах крови этого самого переполнения буфера в стеке. Из пользовательских данных берётся значение, которое преобразовывается в число. Если дальше нет валидации этих данных, жди беды переполнения.

Настала пора заглянуть в саму функцию x_vserv_protocol_body, граф которой показан на рисунке ниже.


_Граф функции x_vserv_protocol_body_

После долгих вечеров и дней реверс-инжиниринга граф функции в стиле «лесенки» практически сразу говорит о том, что в исходном коде была цепочка из if-else-if-else-if-else (возможно, также и switch). И действительно, если внимательно посмотреть на функцию, то хорошо видно, что в каждом из блоков берутся первые байты тела пакета и поочередно сравниваются с “HEXDUMP”, “TALK2ME”, “B64DECO”, “DISCONN”, “STOP!!!”. Если ничего из этого не нашлось, то в консоль выводится строка «Unknown command». Таким образом, понятно, что перечисленные выше строки — команды протокола. При обнаружении одной из них выполнение переходит на соответствующую функцию. Их можно поименовать следующим образом: x_vserv_hexdump, x_vserv_talk2me, x_vserv_b64deco, x_vserv_disconn, x_vserv_stop. Это и есть обработчики команд протокола.

0x45c Пощупаем некоторые обработчики команд vserv

Интересно отметить, что число, которое передано вторым аргументом, нигде не используется в этой функции напрямую, а только передается дальше в обработчики команд протокола. Кроме того, нет и валидации количества принятых данных, то есть программа считает, что ей обязательно пришёл пакет как минимум из 15 байт (хотя это может быть вовсе не так). Чтобы всё-таки убедиться, что второй аргумент, он же len, реально является числом, применяемым как размер данных, обратимся к одному из обработчиков x_vserv_hexdump. Интересующий нас кусок функции приведён на рисунке ниже.


_Второй аргумент x_vserv_hexdump_

Из этого кода видно, что в функции есть некий счетчик, хранящийся в регистре ebp (вероятно, компилятору не хватило регистров общего назначения, обычно ebp не используется в качестве счётчика). Он сравнивается со вторым аргументом, и цикл завершается, когда значение счётчика достигает аргумента, то есть, какое значение мы указали в пакете, столько раз будет выполняться этот цикл.

0x45d Закругляемся на сегодня

0x50 Is this the end?

; {EN} x_vserv_parse_body {EN}

Статья направлена на то, чтобы изложить максимально подробно базовую технику реверс-инжиниринга, которая была бы понятна новичку и он смог бы попробовать изучить другие бинарники. Конечно, мы не коснулись разбора алгоритмов, а фактически только посмотрели, как понять структуру программы и куда вообще лезть после того, как открыл её в IDA Pro.

Если вдруг эта статья окажется не 9-й жизнью котика реверс-инженера, он расскажет об анализе обработчиков протокола VSERV в IDA Pro, поможет написать для него клиент и вместе с читателем поищет уязвимость RCE (она там есть и лежит на поверхности) в этом сервере.

140 / 74 / 18

Регистрация: 21.02.2014

Сообщений: 3,412

1

21.10.2014, 15:12. Показов 9424. Ответов 17


Студворк — интернет-сервис помощи студентам

Добрый день! Извиняюсь если такой вопрос уже был но как в Ida Pro выполнить поиск по radiobutton?
Допустим есть radiobutton и вывод на экран того что он делает нужно найти все строчки кода к нему относящемуся..

Миниатюры

Поиск в Ida Pro
 



0



Programming

Эксперт

94731 / 64177 / 26122

Регистрация: 12.04.2006

Сообщений: 116,782

21.10.2014, 15:12

Ответы с готовыми решениями:

Ida pro
таварищи подскажите де добыть сей софт(ida pro) с кряком google шо-то не помог

Скрипты в IDA Pro Advanced.v6.1
Тринируюсь писать скрипты, вчера уже написал один рабочий.

Хочу удлинить прогу, и в заданое…

IDA PRO загрузить файл
Здравствуйте уважаемые специалисты.
В часто задаваемых вопросах по IDA PRO мало внимание уделено…

IDA PRO. На скриншоте это адреса?
Доброй ночи, спасибо что уделили время, у меня вопросик то что находиться на скриншоте это адресса…

17

140 / 74 / 18

Регистрация: 21.02.2014

Сообщений: 3,412

21.10.2014, 16:13

 [ТС]

2

хорошо допустим я нашел hex значение как в читаемый код то перевести



0



Клюг

7673 / 3188 / 382

Регистрация: 03.05.2011

Сообщений: 8,380

21.10.2014, 16:43

3

Возьмите exescope и картинка прояснится. В утиле OpenWatcom есть wspy — тоже иногда помогает.



1



140 / 74 / 18

Регистрация: 21.02.2014

Сообщений: 3,412

22.10.2014, 09:22

 [ТС]

4

Спасибо, попробую, все же лучше чем не чего.



0



Ушел с форума

Эксперт С++

16458 / 7422 / 1186

Регистрация: 02.05.2013

Сообщений: 11,617

Записей в блоге: 1

22.10.2014, 14:14

5

Я бы пошел таким путем: сначала Spy++ и находим оконную процедуру.
Далее цепляемся отладчиком к процессу и ставим брейкпоинт на нее.
Ну а дальше можно посчитать, к примеру, смещение от image base и
далее в IDA Pro ориентироваться по нему.



1



3174 / 1933 / 312

Регистрация: 27.08.2010

Сообщений: 5,131

Записей в блоге: 1

22.10.2014, 16:53

6

Цитата
Сообщение от Cdelphi78
Посмотреть сообщение

в Ida Pro

Неподходящий инструмент для поиска, лучший вариант — Hiew. Достаточно Demo версии.

У «radiobutton» есть идентификатор ресурса — ResID. Нужно его выяснить (в ExeScope, например).

В зависимости от его размера (обычно, byte или dword), искать один из следующих опкодов (6Axx или 68xxxxxxxx, где взамен xxx подставлен ResID с учетом порядка байт):

Код

6A         PUSH imm8     2        Push immediate byte
68         PUSH imm16    2        Push immediate word
68         PUSH imm32    2        Push immediate dword

Таких мест не должно быть много, а вот уже код по найденным смещениям удобно смотреть в IDA.

Как вариант, для быстрого поиска нужного опкода можно использовать SSF — Stupid Signature Finder.



1



140 / 74 / 18

Регистрация: 21.02.2014

Сообщений: 3,412

23.10.2014, 09:06

 [ТС]

7

Цитата
Сообщение от Убежденный
Посмотреть сообщение

Я бы пошел таким путем: сначала Spy++ и находим оконную процедуру.
Далее цепляемся отладчиком к процессу и ставим брейкпоинт на нее.
Ну а дальше можно посчитать, к примеру, смещение от image base и
далее в IDA Pro ориентироваться по нему.

Пока что не обладаю нужными знаниями по этому методу.

Цитата
Сообщение от gazlan
Посмотреть сообщение

Неподходящий инструмент для поиска, лучший вариант — Hiew. Достаточно Demo версии.

Использовал, открыл искал юникод но дальше не продвинулось

Цитата
Сообщение от gazlan
Посмотреть сообщение

У «radiobutton» есть идентификатор ресурса — ResID. Нужно его выяснить (в ExeScope, например).
В зависимости от его размера (обычно, byte или dword), искать один из следующих опкодов (6Axx или 68xxxxxxxx, где взамен xxx подставлен ResID с учетом порядка байт):

Вот это интересно, но тоже темный лес пока,попробую почитать что нибуть



0



Клюг

7673 / 3188 / 382

Регистрация: 03.05.2011

Сообщений: 8,380

23.10.2014, 13:36

8

Кстати, если прога писана на дельфи, то уместен будет DeDe.3.50.04.1635.



0



3174 / 1933 / 312

Регистрация: 27.08.2010

Сообщений: 5,131

Записей в блоге: 1

23.10.2014, 13:54

9

Цитата
Сообщение от Charles Kludge
Посмотреть сообщение

DeDe

Тогда уж, IDR 2.5.3 :-)

Миниатюры

Поиск в Ida Pro
 



1



140 / 74 / 18

Регистрация: 21.02.2014

Сообщений: 3,412

24.10.2014, 14:22

 [ТС]

10

Цитата
Сообщение от Charles Kludge
Посмотреть сообщение

Кстати, если прога писана на дельфи, то уместен будет DeDe.3.50.04.1635.

Нет я думаю Си, вообще может можно как нибудь сразу в Си отконвертить чтоб без ассемблера



0



Клюг

7673 / 3188 / 382

Регистрация: 03.05.2011

Сообщений: 8,380

24.10.2014, 14:51

11

Цитата
Сообщение от Cdelphi78
Посмотреть сообщение

можно как нибудь сразу в Си

Дык, через hexrays в IDA, совсем влобовую не получится.



0



Модератор

Эксперт по электронике

8804 / 6587 / 894

Регистрация: 14.02.2011

Сообщений: 23,152

24.10.2014, 15:02

12

Цитата
Сообщение от Cdelphi78
Посмотреть сообщение

уже был но как в Ida Pro выполнить поиск по radiobutton?

никак, в смысле вот так вот, написал радиобутон и нашел
для начала нужно узнать кем откомпилирован файл
обычно ида знает основные компиляторы и подключает нужные файлы
а дальше
хватаем класс окна как подсаказалУбежденный, или если это часть ресурсов то смотрим ID(например PeExplorer) потом вылавливаем все Create это если создан программно или ищем ID если это ресурсы
если компилировалось MFC то можно отыскать класс CButton
в общем работа муторная и нудная
дизасемблирование, вообще не простая вещь
попробуй сначала с консольными программами, написал скомпилировал дизасемблировал
иногда проше свою прогу написать чем править чужую



0



Модератор

Эксперт по электронике

8804 / 6587 / 894

Регистрация: 14.02.2011

Сообщений: 23,152

24.10.2014, 15:05

14

Цитата
Сообщение от Cdelphi78
Посмотреть сообщение

вообще может можно как нибудь сразу в Си отконвертить чтоб без ассемблера

нельзя
компиляция необратимый процесс
есть прилуда к Иде которая делает Сиподобные файлы

Цитата
Сообщение от Charles Kludge
Посмотреть сообщение

Дык, через hexrays в IDA,

но уж лучше бы не делала в том коде разобраться хуже чем в ассемблерном



1



3174 / 1933 / 312

Регистрация: 27.08.2010

Сообщений: 5,131

Записей в блоге: 1

24.10.2014, 16:18

15

Есть еще:

Boomerang

This project is an attempt to develop a real decompiler for machine code programs through the open source community. A decompiler takes as input an executable file, and attempts to create a high level, compilable, possibly even maintainable source file that does the same thing. It is therefore the opposite of a compiler, which takes a source file and makes an executable. However, a general decompiler does not attempt to reverse every action of the decompiler, rather it transforms the input program repeatedly until the result is high level source code. It therefore won’t recreate the original source file; probably nothing like it. It does not matter if the executable file has symbols or not, or was compiled from any particular language. (However, declarative languages like ML are not considered.)

C4Decompiler

C4Decompiler is a general, interactive Machine Decompiler for Intel IA Processors (x86 based). It accepts obj and exe files as input, performs a static analysis and generates C source code as output.

PE-bear

PE-bear is a new reversing tool for PE files.

Objective: to deliver fast and flexible “first view” tool for malware analysts. Stable and capable to handle malformed PE files.

DCC Decompiler, The dcc Decompiler

The dcc decompiler decompiles .exe files from the (i386, DOS) platform to C programs. The final C program contains assembler code for any subroutines that are not possible to be decompiled at a higher level than assembler.

The analysis performed by dcc is based on traditional compiler optimization techniques and graph theory. The former is capable of eliminating registers and intermediate instructions to reconstruct high-level statements; the later is capable of determining the control structures in each subroutine.

ExeToC Decompiler

Decompile win32 program and DLL to C++ step by step. Allow some interactive.

Main functions already work:

*support if/else/for/do/while/break/switch case/continue
*support API
*support C++ head file load
*support standard library function recognize

REC Studio

REC Studio is an interactive decompiler.

It reads a Windows, Linux, Mac OS X or raw executable file, and attempts to produce a C-like representation of the code and data used to build the executable file.
It has been designed to read files produced for many different targets, and it has been compiled on several host systems.

SmartDec

SmartDec is a native code to C/C++ decompiler. It is currently in its beta stage. However, most of the functionality is already in place and can be used. If you are interested in checking out the beta version, visit the downloads page.



3



140 / 74 / 18

Регистрация: 21.02.2014

Сообщений: 3,412

24.10.2014, 16:39

 [ТС]

16

Цитата
Сообщение от gazlan
Посмотреть сообщение

Есть еще:

Ха Ха)) тут работы на пол года вперед), кстати утилитки какие вы мне дали как они вообще работают я запускаю их и они закрываются. Ладно пока решил проблему другим способом, отложу изучение дизасемблирование до лучших времен



0



3174 / 1933 / 312

Регистрация: 27.08.2010

Сообщений: 5,131

Записей в блоге: 1

24.10.2014, 17:35

17

Цитата
Сообщение от Cdelphi78
Посмотреть сообщение

запускаю их и они закрываются

Использовать в консоли (из командной строки).

Миниатюры

Поиск в Ida Pro
 



0



Модератор

Эксперт по электронике

8804 / 6587 / 894

Регистрация: 14.02.2011

Сообщений: 23,152

24.10.2014, 18:08

18

Цитата
Сообщение от Cdelphi78
Посмотреть сообщение

тут работы на пол года вперед),

оптимист
Годы
и то никогда не сможешь сказать знаю все



0



Not a stupid question at all. Even the most seasoned reverse engineers run into issues with this task under sub optimal conditions. Like many challenges in this dark art, the solution, or strategies are «reversed» from conventional problem solving. Very poor attempt at humor… This is what happens to you 30 years later when you’ve been staring at a 8gb idb of anti-* for two sunsets, as a hobby.

So… You’re probably thinking: If there were some strings or easily identifiable numbers I could search for them, and get a cross-reference to the code I’m searching for. That would be nice wouldn’t it.

In reality the various metadata is often optimized or obfuscated in the targets of your analysis. Much later you’ll cry tears of joy when you find a pdb sitting next to a large heavily obfuscated cpp executable.

Old man tip: Massive malware analysis repos, e.g. VirusTotal, allow you to do some interesting searches. You could for example do a search for: The string ReleaseTargetApp64.pdb, Signer:»TargetVendor», File version:1.2.x. While malware analysis sites specifically do not directly support the uploading of pdb files due to the obvious disclosure risks, they do however maintain the compressed archive where the TargetExe.exe originated, which usually is where the pdb would also be located. ;)

Without strings and easily identifiable constants you have a wide variety of other characteristics you can pursue and that often will be even more effective in locating what it is you seek.

Constants

If the routine you are examining incorporates a little mathmatics the compiler will optimize the algorithmic code written by the developer into reduced expressions using specific, optimized constant values and data structures.
There are quite a few good papers and tools out there now on this topic. You could go after a few PHD(s) and spend a few years studying them write a plugin that will be not run on the next version of IDA or do what I do: Find a genuine subject matter expert in that field that has already done and use their wares, or bribe them with copious amounts of booze, and/or money and high octane life experiences. Everyone wins. Every reverse engineer needs a bad ass math ninja in their corner, especially one with a little swagger and grit. They do exist, and good luck on that. Seriously, bring me the five most brilliant mathematicians and I’ll show you a dinner tab that isn’t getting paid because they’re arguing for an hour over how much each one should pay. Hire the one that pays the whole bill and slow walks to the bar.
For now a nice gentleman has been carrying the torch on the original Sigsrch/signsrch/Signsrch:
https://github.com/ajkhoury/IDA_Signsrch-7.0

Machine Code Signatures

Machine code and data themselves area a great resource for applying a signature solution. An offset value from a register is can be a characteristic of the size of data structure or the location of a member within that data structure. The larger and more complex the structure or class, the easier it is to identify as the signature can be further enhanced. There are a lot of variations to this but I’m sure you get the idea. For this strategy I’d suggest three things:

  1. Lightweight Wildcard Lib

    Integrate a lightweight popular third party signature solution into
    your project that is used by people to solve the exact problem
    you’re faced with. Game hackers have to solve this constantly to get
    their offsets for routines they need to hook and data that they need
    to manipulate. Check out something like this:
    https://github.com/wanttobeno/x64_AOB_Search/blob/master/AobScan/Demo.cpp

  2. F.L.I.R.T.

    Ilfak’s and team provided a solid framework to tackle this a while
    ago and it’s been one of my key tools ever since. I crawl repos for
    popular libraries and SDK’s then I generate signatures for
    theroutines. Crypto, netcode, Compression/Algorithmic, runtimes,even
    focused components like ML engines, sandboxes and crashhandlers. You
    have to tune it a little bit and defniitely avoid making signatures
    for routines that are only a few instructions in size, you’ll wreck
    a good workspace with ambiguous symbols.

  3. Ignore Him

    Ignore the person that replies to this thread and suggests an
    alternative.

    If Mr. Miyagi could read machine code in a few thousand
    different architectures he might be able to paint Ilfak’s fence.
    I’ve had Ilfak’s tools in my kit before cybersecurity was even a
    word and Hackers was a hipster movie trying to be like Sneakers that
    wanted to group into Wargames.

Relationships, Cross References and RTTI

C++ is a real pain when you first encounter it and will be for a while down the road. If you want to get of the curve and do something I should’ve done the first few years into my career. C/C++ ABI: Think of it as a basic set of guidelines that OS and compiler vendors try to adhere to for the benefit of compatibility. The benefit to us is its one of the few sources of insight into how object oriented languages are consumed and laid out in memory. From a brief search I found this.:
https://www.oracle.com/technical-resources/articles/it-infrastructure/stable-cplusplus-abi.html

If any other readers have a link to a modern introduction and overview of the primary ABI(s), it would surely be appreciated here as a reference.

Class Informer (IDA Plugin)

https://sourceforge.net/projects/classinformer/

While IDA does have support for parsing RTTI structures to annotate c++ classes this plugin’s last update took it up a notch and it does a great job analyzing virtual tables like those used by C++ classes.

Devirtualize

https://github.com/ALSchwalm/devirtualize

A few years back I stumbled on this IDA plugin, well written, lightweight and relatively easy to customize if needed:

I’d recommend installing it and debug step through it to get an idea how the author detects c++ classes and builds the relationships of its members to something useful in IDA. Then, if you want to really dig in, take on optimizing the code to detect things and solve problems that the original developer did not. Everybody see’s things differently, that’s the reason that for over 25 years now, there have been dozens of remote root vulnerabilities found in the exact same hundred lines of Sendmail code, a single routine that countless auditors have reviewed previously.

Symbol Porting

If you have partial source code that was compiled into your analysis target you can build an executable or library with symbols, then port those over using something like BinDiff. Over several major version those guys have greatly simplified an otherwise very challenging and tedious task. The best part is they decided to release it as a free to download product now.

BinDiff
https://www.zynamics.com/software.html

I’d recommend using whatever tools you have at your disposal to identify the OS version (major/minor), architecture, compiler version, and run time version (e.g. msvcrtX) on your analysis target. Then replicate those as closely as possible in the environment you are building your code with symbols. If the code your are porting symbols for is almost always integrated as a library (e.g. zlib.lib), rather than source, then you’re in luck. Libs will be much better targets due to the reduction of compiler steps that may otherwise produce different target code.

Runtime Analysis

There are a lot of run time solutions that will observe data (e.g. class istance pointers) as it flows through code and use those records to dress up code. There are some interesting and heavy computer science/mathematics areas of study that have attracted some real bright folks into further solving this. In all the data flow, taint analysis, tracing, emulation, and other run time methods I’ve deployed over the years, I find myself doing it statically by hand now. A little code here and there to automate redundant tasks of course. If the code can be executed without requiring a secret, everything needed to execute it is in there somewhere, or somewhere close by. I’m very likely a masochist when it comes to reverse engineering but I think you have to be if you enjoy spending your life living inside a «black box».
If anyone ever gives you grief over a what you feel, is a simple question, they are either very young, or very talent less and will never truly shine. The most awe-striking, brilliant people I’ve had the pleasure to work with were always wide-eyed and exponentially humble. They’d drop everything, miss a critical deadline just to transfer knowledge, learn something themselves, share the experience and tackle an old demon once again. If it wasn’t for them this reply wouldn’t have been remotely possible.

Contents

  • 1 Introduction
    • 1.1 Prerequisites
    • 1.2 Links
  • 2 Shortcuts
  • 3 Searching
    • 3.1 Find all occurrences
    • 3.2 Searching inside sub-views with filters
      • 3.2.1 Finding virtual function tables
    • 3.3 Binary search
      • 3.3.1 Wildcards
    • 3.4 Text search
  • 4 Structures
    • 4.1 Creating new struct types in decompiled view
    • 4.2 Importing C header files
      • 4.2.1 Reconstructing a virtual function table
  • 5 X-Refs
    • 5.1 Finding vtable for a reference
  • 6 Byte patching
    • 6.1 IDA view
    • 6.2 Hex view
    • 6.3 Applying patches to the file
  • 7 Synchronizing views
  • 8 Python plugins
    • 8.1 Skeleton python plugin
    • 8.2 Auto loading plugins
  • 9 Honorable mentions

Introduction

This tutorial is aimed towards IDA Pro 7.0. we will be covering the basic features and how to use them together with a few tricks and quirks.

Prerequisites

  • Basic understanding of any assembly language and C/C++.
  • Being familiar with IDA and its user interface, nothing crazy though.

Links

  • Shortcut cheat sheet
  • IDA Pro Book, 2nd Edition
  • Links from hexrays
  • IDA Python documentation

Shortcuts

First of all visit the cheat sheet

Here is a few shortcuts that are essential to know

  • X — Cross referencing
  • Tab — Switch between decompiled view and IDA view
  • Escape — The back arrow/go to previous position in current view
  • Ctrl+Enter — The forward arrow/go to next position in current view
  • Y — Change the type of the selected/marked function/variable
  • P — Make function at selected address inside IDA view
  • N — Rename selected/marked reference
  • * — Make array inside stack view

Searching

You have to mark a window to search in before you can search for anything, the search feature only works with a few sub-views for example IDA views, Hex views and pseudo-code views from the decompiler.

Find all occurrences

If this is enabled, the search make a list with all the occurrences of what you were searching for, which is very helpful if you are not entirely sure what you are looking for, I would almost recommend that this is on at all times, so you don’t miss something important while searching.

IdaProFindAllOccurrences.png

Searching inside sub-views with filters

This only applies to some sub-views such as Functions(Shift+F3), Names(Shift+F4) and Strings(Shift+F12), there is probably more but these are some of the most frequently used.

IdaProFilterWindow.png

You can also click/select/mark a sub-view and start typing what you want to search for, you need to know the exact starting characters you want to find with this.

IdaProSubViewSearch1.png

You can also ctrl+f inside a sub-view to search, this will result in the same as a filter with contains.

IdaProSubViewSearch2.png

Finding virtual function tables

Open the Names sub-view, and either mark or right click inside it to open the filter window, where you can add the following filters

IdaFilterExample.png

Double clicking on any of these results will take you directly to the virtual function table.

Binary search

When using binary search, IDA will search all the bytes in the file the selected/marked sub-view is associated with, this makes searching quite fast, pretty much like sig scanning.

You can also search for strings with this search feature, however you are limited to the strings or byte sequences that make up a strings in the file you are searching, if you want to search for some text that got generated inside IDA view for example «sp-analysis failed» you have to use the text search feature.

Wildcards

You can use wildcards in your binary searches by giving it an hex encoded string with question marks as the wildcards

48 65 6c 6c 6f 20 57 6f 72 6c 64
48 65 6c 6c 6f 20 57 6f ?? ?? 64
48 65 6c 6c 6f 20 57 6f ? ? 64

Text search

When using text search, IDA will search all text within the selected/marked sub-view, so using it on IDA view’s can take some time depending on the size of the disassembled file.

You can use regex with this search feature, I cant come up with any use cases other than this link, but even this is quite useless if you are looking at a game engine that has tons of the same instructions.

Structures

You can create your own structures that you can apply to variables in IDA view or the decompiled view, you can do it manually in the structures sub-view, or import C header files.

It is quite tedious to do it manually, so I am just going to skip that entirely and jump straight to importing C header files.

Creating new struct types in decompiled view

You can make IDA guess a structure definition by right clicking variables that has structure like usage e.g. casting with offsets like so:

Pre create new struct.png

v5 in this case, so you right click the variable then select «Create new struct type…» and you will be prompted with a new window:

Create new struct window.png

You can also apply your own names/fields in here, when ready click OK and now the decompiled code looks something like this:

Post create new struct.png

This is a quite limited feature yet very powerful if used in combination with the decompiler.

When making C headers for IDA keep in mind that this is very low level, the parser can only understand default types, you can still define your own types with:

typedef unsigned char uint8_t;

So you cant just include your sdk.h with 10k lines of class definitions, you have to cherry pick what you want and slowly build a nice IDA header file you can use for all of your IDA projects.

Reconstructing a virtual function table

Default decompilation of an area with virtual function calls

IdaVtableExamplePre.png

For unknown vtables you can use something like this

struct my_vtable
{
	void* unknowns[0x1000];
};

struct my_class
{
	my_vtable* vtable;
	unsigned char data[0x10000];
};

IdaVtableExamplePost1.png

If you have a vtable where you know the names and function types of the functions you can do something like this

typedef void(__thiscall* known_function)(void* thisptr, const char* id, int number);
struct known_vtable
{
	void* unknowns[13];
	known_function some_known_function;
};

struct known_class
{
	known_vtable* vtable;
};

IdaVtableExamplePost2.png

X-Refs

This is a pretty simple feature, there is no tricks to using it efficiently, it just takes practice.

Finding vtable for a reference

Xref your reference, and sort by Type in most cases there will only be 1 write instruction to this kind of references.

IdaProXrefExample2.png

Byte patching

Byte patching in IDA is quite tedious and is known to have buggy behavior. If you are working with a project that requires a lot of byte patching I would recommend looking at binary ninja’s byte patching features.

IDA view

If you want to patch things relative to what you see in IDA view, you have to use the drop down menus like shown here

IdaProBytePatch1.png

Hex view

Select the hex view and press F2 or right click and use the menu, you can edit inside the hex encoded text or the ASCII representation of said hex encoded bytes.

Applying patches to the file

When applying patches to a modified file, it is highly suggested that you take backup since this feature is known to be buggy.

Synchronizing views

You can synchronize views in IDA, this is useful if you want to find something and know how the decompiled view should look like roughly.

Example video of usage and how to do it

Python plugins

Main source of documentation will come from here its a bit tricky to navigate efficiently in here, but it will do fine for now.

Skeleton python plugin

import idaapi

class MyPlugin(idaapi.plugin_t):
    flags = idaapi.PLUGIN_HIDE | idaapi.PLUGIN_PROC
    comment = "Comment string"
    help = "Help string"
    wanted_name = "Plugin name"
    wanted_hotkey = ""

    def init(self):
        idaapi.msg("Initn")
        return idaapi.PLUGIN_KEEP

    def run(self):
        idaapi.msg("Runn")

    def term(self):
        idaapi.msg("Termn")

def PLUGIN_ENTRY(*args, **kwargs):
    return MyPlugin()

Auto loading plugins

Simply moving file.py inside <installation-folder>/plugins/ will make IDA attempt to autoload the plugin upon start

Honorable mentions

Features that didn’t make it into the page, but should have a page of it’s own.

  • Debugging with IDA

Понравилась статья? Поделить с друзьями:
  • Как найти поисковик на компе
  • Как найти человека в юрге на
  • Как составить авансовый отчет при оплате корпоративной картой
  • Как найти свои минусы тест
  • Как найти локальные экстремумы в задаче