Введение в реверсинг с нуля используя IDA PRO. Часть 14.

Дата публикации 13 сен 2017 | Редактировалось 14 сен 2017
Это курс будет смешанным, и он будет включать в себя разные темы связанные с реверсингом (мы уже говорили о статическом реверсинге, а также будем говорить об отладке, распаковке, эксплоитинге).

В этой главе мы будем распаковывать файл CRACKME.EXE упакованный последним UPX. Это не означает, что мы собираемся cделать много частей только с распаковкой, мы будем менять темы разговора, и перемешивать различные темы, для того, чтобы никто не скучал, так что у нас будут уроки по распаковке, смешанные с другими темами.

Упакованные файлы

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

Существует тысяча видов упаковщиков и большинство из них являются протекторами, которые изменяют IAT или таблицу импорта, а также изменяют ЗАГОЛОВОК, они добавляют анти-отладочный код, чтобы предотвратить распаковку и восстановление исходного файла.

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

1.png

Мы будем помещать галочку в MANUAL LOAD и снимать другую с пункта CREATE IMPORTS SEGMENT так как нам необходимо, чтобы у нас были загружены все секции программы,
и если она может влиять на галочку CREATE IMPORTS SEGMENTS, то я про это не знаю, но IDA советует снять эту галочку при работе с упакованными файлами.

2.png

Это начало или EP файла PACKED_CRACKME.EXE, мы видим, что она находится по адресу 0x409BE0, в то время как оригинальная EP находилась по адресу 0x401000, как мы видим ниже.

3.png

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

OРИГИНАЛЬНЫЙ

4.png

УПАКОВАННЫЙ

5.png

Мы видим, что секция UPX0 упаковщика заканчивается по адресу 0x409000, в то время как в исходном файле все секции расположены в памяти начиная с адреса 0x401000 и заканчиваются по адресу 0x408200.


Здесь мы начинаем говорить о виртуальной памяти, т.е. когда программа запускается, она может иметь 1 килобайт на жестком диске, а резервировать 20 килобайт или сколько она пожелает в памяти.

Это возможно видеть в IDA, например, по адресу начала секции исходного файла 0x401000 мы видим.

6.png

Вышеупомянутая секция (SECTION SIZE IN FILE) занимает 0x600 байт в файле, в то время как в памяти (VIRTUAL SIZE) она занимает 0x1000 байт.

В то время, как у упакованного файла, если мы идём по адресу 0x401000, который является началом секции UPX0, мы видим.

7.png

Мы видим, что есть одна секция размером 0 байтов на диске, но в памяти она будет занимать 0x8000 байт, т. е. это означает, что резервируется пустое пространство, для создания здесь исходного кода программы и затем программа переходит туда, чтобы выполнить этот код, так как есть достаточно пространства, чтобы сделать это.

8.png

Также мы видим, что адрес 0x401000 имеет впереди префикс DWORD_, который означает, что его содержимым является данные типа DWORD.

Знак (?) означает, что место только зарезервировано, т.е. оно не имеет содержимого и DUP или умножитель, означает, что этот DWORD умножается на 0xC00 и в итоге получится 0x3000 зарезервированных байт.

9.png

Затем по адресу 0x404000 есть 0x1400 DWORD символов (?), это место тоже зарезервировано.

10.png

То есть, в памяти резервируется 0x8000 байт, чтобы загрузить туда программу.

11.png

Также мы видим, что по адресу 0x401000 есть ссылка на исполняемый код, позже мы увидим, что это он и что он делает.

12.png

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

Если мы видим ссылки по адресу начала секции 0x409000.

Мы видим, что ниже (DOWN) есть ссылка в исполняемой части, если мы щелкнем на неё.

13.png

14.png

Мы видим, что в СТАБЕ после EP загружается адрес 0x409000 (запомните СМЕЩЕНИЕ впереди).

Если мы нажмём на пробел, мы увидим там

15.png

Что код СТАБА находится в той же секции UPX1 под упакованным кодом исходной программы, в секции UPX1 у нас есть сохраненные байты исходной зашифрованной программы и код СТАБА находящийся по адресу 0x409BE0.

Нам не нужно быть гением, чтобы знать, что он будет читать байты по адресу начиная с адреса 0x409000, он применит некоторые операции над ними и сохранит их по адресу 0x401000. EDI = ESI - 0x8000.

16.png

17.png

Другими словами, видно, что он будет использовать содержимое ESI как ИСТОЧНИК откуда он будет читать данные, он будет применять к ним некоторые операции и сохранять их в содержимое EDI, для создания программы.

Ранее мы сказали, что по адресу 0x401000 есть ссылка на исполняемый код, если мы сделаем двойной щелчок по этой ссылке.

18.png

Мы видим, что есть переход в 0x401000.

19.png

JMP NEAR это прямой переход по адресу, который находится рядом с ним, т.е. он будет переходить по адресу 0x401000, очевидно, здесь, позже, выполнится весь СТАБ и создастся исходный код, он будет переходить в OEP по адресу 0x401000, что будет OEP, которая отличается от EP СТАБА тем, что находится по адресу 0x00409BE0.


Мы будем вызывать OEP или ORIGINAL ENTRY POINT в ENTRY POINT исходной программы, очевидно, так как это упакованная программа, то мы не знаем где она находится и только поскольку мы у нас есть исходная программа, мы можем знать, что OEP была по адресу 0x401000.

20.png

Очевидно, когда у нас есть упакованная программа, то мы не знаем её OEP, потому что мы не имеем исходной программы, поэтому нам нужно научиться её находить, следовательно, когда СТАБ закончит выполнять все свои трюки и закончит создавать исходный код, он будет переходить туда для выполнения программы, почти всегда первая инструкция кода, которую он выполняет в созданной секции, будет OEP.

Мы могли бы установить BP в этот JMP на OEP, чтобы увидеть есть ли там оригинальная программа, которая уже создана, давайте попробуем.

21.png

Давайте выберем отладчик LOCAL WIN32 DEBUGGER и давайте нажмём START DEBUGGER.

22.png

Здесь я останавливаюсь на переходе в OEP, мы трассируем его с помощью F8.

23.png

Мы нажимаем YES для того, чтобы отладчик интерпретировал как КОД первую секцию UPX0, которая была определена как ДАННЫЕ.

24.png

Мы видим, что отладчик уже распаковал код и теперь переходим туда, чтобы выполнить его. Код очень похож на код оригинальной программы по адресу 0x401000, хотя, мы видим, что если мы захотим перейти в графический режим, у нас ничего не получится, потому что код не определен как функция (loc_401000), но мы сделаем это автоматически.

Здесь есть скрытое меню в левом нижнем углу, делая правый щелчок, я выбираю REANALYZE PROGRAM.

25.png

Мы видим, что кликнув по адресу loc_401000 отладчик меняет на тэг на sub_401000, который показывает, что сейчас это функция, так что теперь мы можем переключить его в графический режим с помощью пробела.

26.png

Сейчас это выглядит намного лучше.

27.png

Различие, которое мы видим состоит в том, что оригинальный файл показывает по адресу 0x401002 вызов CALL GetModuleHandleA, в то время как запакованный показывает CALL sub_401056, давайте посмотрим, что есть внутри этого CALL.

28.png

Давайте посмотрим различия с исходным файлом, если мы войдём в CALL GetModuleHandleA в исходном файле.

29.png

Также существует косвенный переход, но здесь, IDA обнаруживает, что это переход к API, а в упакованном такого нет, но где тогда переход в упакованном файлe?

30.png

Содержимым по адресу 0x403028 является смещение(OFF_), т. е. адрес API функции GetModuleHandleA и в исходной программе это тот же самый адрес в секции IDATA и он содержит также адрес той же самой API.

31.png

Несмотря на то, что они в конечном итоге переходят в одно и то же место, существует одна очень важная разница, которую мы увидим позже.

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

Сначала в СЕГМЕНТАХ

32.png

Я проверяю, что все секции упаковщика имеют букву L, что означает, что они будут загружены в ЗАГРУЗЧИК, как мы видим в образе, я могу даже добавить какую-либо DLL или сегмент, который я хочу, чтобы он был в в статическом анализе, для этого делаем ПРАВЫЙ ЩЕЛЧОК → EDIT SEGMENT на строке, которую мы хотим добавить в ЗАГРУЗЧИК.

33.png

На сегментах, которые мы хотим, чтобы они добавились, мы ставим галочку в LOADER SEGMENT, в этом случае мы оставим только сегменты УПАКОВЩИКА, но про это хорошо знать, что мы можем добавить и другие.

34.png

35.png

Затем опция TAKE MEMORY SNAPSHOT будет сохранять сегменты, которые мы пометили как ЗАГРУЖАЕМЫМИ как код, который они имеют. (НЕ ПУТАЙТЕ ЭТО С ДРУГОЙ ОПЦИЕЙ FILE → TAKE DATABASE SNAPSHOT, которую мы изучали ранее)

Мы видим, что если я останавливаю ОТЛАДЧИК, и конечно я остаюсь в ЗАГРУЗЧИКЕ, и я иду по адресу 0x401000 вместо того, чтобы быть пустым как раньше, сейчас появляется код, который мы скопировали, когда мы были в OEP и который сейчас доступен для того, чтобы сделать статический реверсинг как и все сегменты, которые имеют букву L, конечно, если мы снова запустим ОТЛАДЧИК, код исчезнет, потому что он будет перезаписываться байтами, которые будут там, когда секция инициализируется в ОТЛАДЧИКЕ, поэтому, если нам нужна база данных со статическим анализом, мы должны скопировать ее в другую папку и открыть ее в другой копии IDA для комфортной работы.

Если я запущу снова отладчик и остановлюсь в той же EP до выполнения СТАБА, я увижу, что область по адресу 0x401000 снова пустая.

36.png

37.png

То, что мы сохранили в базе данных теперь потеряно, потому что в ОТЛАДЧИКЕ информация ЗАГРУЗЧИКА была перезаписана байтами, которые инициализировала секция UPX0, поэтому, если это информация необходима для статического реверсинга, как я уже говорил ранее, после нажатия TAKE MEMORY SNAPSHOT её нужно скопировать в другой каталог, перед тем как снова запускать отладчик.

Поскольку, я очень надоедливый(Это Рикардо про себя :) ), то я буду искать второй способ получит OEP, который ищет первую инструкцию, которая выполняется в первой секции, это другой метод, который иногда может работать.

Я запускаю снова УПАКОВАННЫЙ ФАЙЛ в ОТЛАДЧИКЕ, останавливаюсь в его EP.

38.png

Я иду в первую секцию, где она начинается по адресу 0x401000.

39.png

Я установил BP с помощью F2. Я установил его для остановки по исполнению или EXECUTE. Отладчик будет останавливаться только при выполнении, а не при чтении или записи. Поскольку он будет останавливаться при копировании кода и его создании, я не хочу этого. Я просто хочу, чтобы он перешел, когда код уже создан, отладчик остановится на первой инструкции, которую он выполняет, и поскольку я не знаю, где это место, я устанавливаю BP на ВЫПОЛНЕНИЕ, который охватывает всю секцию (0x8000 байт).

40.png

Он пометил все инструкции в красный цвет.

41.png

Я выключаю два других BP через DEBUGGER → BREAKPOINT → BREAKPOINT LIST.

42.png

ДЕЛАЕМ ЩЕЛЧОК ПРАВОЙ КНОПКОЙ И ВЫБИРАЕМ DISABLE.

43.png

И сейчас, если я нажму RUN.

И я вижу, что первая инструкция, на которой остановился отладчик, находится в секции созданной недавно, т.е. в этом случае по адресу 0x401000 находится моя найденная OEP.

44.png

Таким образом, использую этот метод и мы находим OEP, адрес которой равен 0x401000, теперь я удаляю BP.

После повторного анализа у меня снова есть эта функция.

45.png

Т.е. до сих пор мы получали OEP и останавливались на ней, используя два разных метода, мы могли бы сделать СНИМОК созданного-загруженного кода, единственное, что нам для этого не хватает, так это сделать ДАМП и ВОССТАНОВИТЬ IAT, чтобы получить распакованный исполняемый и функциональный файл.

До 15-той части, где мы закончим с этим.

Перевод на английский: IvinsonCLS
Перевод на русский с испанского+английского: Яша_Добрый_Хакер(Ростовский фанат Нарвахи).
Перевод специально для форума системного и низкоуровневого программирования - WASM.IN
14.09.2017

16 13.134
yashechka

yashechka
Ростовский фанат Нарвахи

Регистрация:
2 янв 2012
Публикаций:
90

Комментарии


      1. yashechka 21 ноя 2018
        Сейчас пока не скажу, только при практике когда сам буду делать.
      2. CrawlUp 21 ноя 2018
        Здесь рассказывается как подгрузить использумые библиотеки для статического анализа, но эти библиотеки подгружаются в виде данных, а как сделать из них функции?
      3. yashechka 14 авг 2018
        Все верно.
      4. texaciri 13 авг 2018
        "Ранее мы сказали, что по адресу 0x401000 есть ссылка на исполняемый код, если мы сделаем двойной щелчок по этой ссылке.
        Мы видим, что есть переход в 0x401000."

        Мне кажется тут всё же должно быть: "...на адрес 0x401000 есть ссылка из исполняемого кода ..."
        yashechka нравится это.
      5. yashechka 29 янв 2018
        Всё очень верно.
      6. Имя 28 янв 2018
        "создастся исходный код, он будет переходить в OEP по адресу 0x401000, что будет OEP"
        Наверное, "создастся исходный код, он будет переходить по адресу 0x401000, где будет OEP"

        "и только поскольку мы у нас есть исходная программа, мы можем знать, что OEP была по адресу 0x401000."

        "и только поскольку у нас есть исходная программа, мы можем знать, что OEP была по адресу 0x401000." Но если заморочиться, то понятнее русскому человеку будет так:
        "Мы будем вызывать OEP (или ORIGINAL ENTRY POINT) в ENTRY POINT исходной программы. Так как это упакованная программа, то очевидно, что мы не знаем где находится OEP и лишь потому, что у нас есть еще и исходная программа, то мы знаем, что OEP была по адресу 0x401000."
        Но это лишь мое ИМХО)
        yashechka нравится это.
      7. yashechka 28 янв 2018
        Имя нравится это.
      8. yashechka 28 янв 2018
        hjujet и Имя нравится это.
      9. Имя 28 янв 2018
        Спасибо большое за ответ, а упакованный файл есть? Я зашел на сайт, но ни слова по-испански не знаю.
      10. Имя 26 янв 2018
        Спасибо, конечно, за перевод, но как скачать crackme.exe? Тяжело по скринам ориентироваться.
        yashechka нравится это.
      11. yashechka 17 сен 2017
        Без ПДФ я тогда не заработаю на ПК :lol: Я вот думаю, может в киви зарегестрироваться?
        gavr_kadet нравится это.
      12. presler 17 сен 2017
        Очень круто, спасибо! Может забить на перевод в pdf и лучше быстрее переводить следующие части?
        gavr_kadet и yashechka нравится это.
      13. yashechka 14 сен 2017
        ПДФ отложил до выходных, решил что лучше новой главой побаловать 8)
        gavr_kadet нравится это.
      14. yashechka 14 сен 2017
        Ввиду того, что 13 глава была маленькая и неинтересная, вот что пришлось сделать Яше - не спать два дня, не есть, даже на работу не ходить и вот результат перед Вами. Прошу к обсуждению и поиску ошибок :)
        gavr_kadet нравится это.
      15. yashechka 14 сен 2017
        Вы не поверите, но появилась 14 глава :)
        gavr_kadet, tfs_cradle и presler нравится это.