1. Если вы только начинаете программировать на ассемблере и не знаете с чего начать, тогда попробуйте среду разработки ASM Visual IDE
    (c) на правах рекламы
    Скрыть объявление

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

Дата публикации 12 апр 2019 | Редактировалось 17 май 2019
Проблема здесь заключается в том, что в первом вызове MEMCPY функция DESTINATION является P_DEST, откуда она получает значение, возможно, наше, с размером 0x20, но здесь не ясно, кто является источником MEMCPY, кажется, что программа вычисляет его в той же функции, поэтому нам придется немного проанализировать её, чтобы увидеть, откуда исходит SRC и, конечно, наше значение, которое будет в первом WORD этого буфера, как SRC, так и DESTINATION, так как программа копирует в другие первые 0x20 байтов.

Я уже реверсировал этот блок, так что вы увидите некоторые имена, которые уже установлены, но я объясню немного, что внутри в функции A_MEMCPY есть еще одна, которая, наконец, переходит к функции MEMCPY.

1.png

Здесь это CALL который копирует данные.

2.png

Внутри этой функции.

3.png

Это было бы предполагаемое место для падения. Если мы передадим значение меньше 0x20, которое будет вычитаться из 0x20 и будет отрицательного размера.

Переименуйте DST как P_DST, так как это указатель, который указывает на буфер стека, который здесь не виден, но если вы проследуете по ссылкам, чтобы увидеть, откуда он взялся.

Мы видим, что это аргумент этой функции. Если я посмотрю на ссылку.

4.png

5.png

Также это аргумент типа указатель.

6.png

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

7.png

И в этой ссылке, это переменная типа указатель также которая называется SRC. Давайте посмотрим откуда она идет.

8.png

Мы видим, что это буфер в стеке откуда берется адрес и сохраняется в переменную указатель SRC.

9.png

Давайте посмотрим длину буфера.

10.png

Он равен 2052, т.е. 0x804

Python>HEX(2052)

0x804

Поэтому если мы сможем скопировать чуть больше 0x804 произойдет переполнение. Мы уже видели, что можно создать с помощью вычитания отрицательный размер, поэтому мы можем переписать весь стек, включая SEH, если у него есть COOKIE.

Мы видим, что перед возвратом из этой функции, которая имеет буфер есть проверка COOKIE.

11.png

Мы также можем избежать этого перезаписав SEH, так что давайте продолжим.

12.png

В последнем вызове MEMCPY, чтобы увидеть, откуда берутся данные которые будут копироваться здесь, мы видим, что есть инструкция LEA, результатом которой является указатель на SRC, есть вызов EDX * 2 внутри инструкции LEA, поэтому я предполагаю, что регистр EDX будет смещением, так как указатель не умножается, и если смещение, а регистр EAX будет базовым указателем буфера SRC, поэтому я поставил P_SOURCE, возможно, регистр EDX равен 0 в начале и в конце копирует из начала буфера, указанного P_SOURCE.

Хорошо. P_SOURCE это переменная типа указатель. Давайте вернемся назад, и посмотрим откуда она взялась.

13.png

Мы видим, что здесь программа сохраняет его и что оставляет поле 0xC структуры, и поскольку я понятия не имею что это, я назвал его как STRUCT_SIZES. Вы увидите почему это так дальше. Но может подойти и любое имя.

Так я создал маленькую структуру из 4 байт и назвал её так.

14.png

15.png

Мы смотрим выше, потому что на данный момент это не имеет большого значения, что SIZE_MEMCPY сравнивается с вычитанием первыми двумя DWORDS структуры, которые я назвал SIZE1 и SIZE2, и если SIZE_MEMCPY меньше, чем вычитание обоих, программа будет использовать это, если не другой.

16.png

17.png

Мы видим также, что P_SOURCE структуры STRUCT_SIZES используется раньше и что он не сохраняется в этой функции, поскольку при просмотре всех мест, которые использует P_STRUCT_SIZES, нет ни одного, который бы сохранял указатель в этом поле.

18.png

Всего лишь читаем здесь. Давайте посмотрим на ссылку.

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

19.png

Давайте проанализируем здесь формулу как рассчитывается указатель на структуру P_STRUCT_SIZES.

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

20.png

В регистр ECX помещается NUMERO_ELEMENTOS. Возможно это смещение и затем идет добавление числа 4, другими словами из фиксированной глобальной переменной. Я могу найти её содержимое, добавив 4 b получить указатель на структуру в которой 4-тый DWORD будет иметь указатель на источник.

Важно видеть, что SRC происходит из глобальной переменной, потому что, поскольку информация передается между потоками. Очень вероятно, что будет использоваться эта переменная для сохранения в потоке RECV и затем поднимать ее в другом потоке.

Если мы запустим отладчик, мы увидим, что в глобальной переменной BASE_DE_SOURCE есть указатель. В моем случае он равен 0x1EBEBBB8.

21.png

Как мы помним, что к этому значению программа добавляет 4 и находит содержимое, которое является указателем на P_STRUCT_SIZES.

22.png

К содержимому BASE_DE_SOURCE я добавляю 4 и это содержимое - это P_STRUCT_SIZES. В моем случае это равно 0x2AB0038. Если я пойду туда и нажму T.

23.png

Поле 4 (0xC) является указателем на источник. Проще всего было бы перейти туда, где пусто, и поместить BPM, чтобы посмотреть, скопирую ли я туда свои фрукты и где это происходит.

24.png

25.png

Мы видим, что отладчик остановился здесь.

26.png

И мы видим, что копируются мои фрукты.

27.png

Если мы посмотрим на CALL STACK.

28.png

Мы видим, что есть путь от LEYENDO, который проходит через SWITCH и который пишет там, и мы можем продолжить туда, где программа копирует данные.

Мы видим, что второй раз копируется знаменитый 0x3E, который многие нашли в цикле, вместо нашего значения, поэтому мы знаем, куда идти и возможный путь. Теперь, когда нам ясно, мы должны продолжать смотреть на SWITCH.

Также если мы посмотрим немного на способы получить эту копию из SWITCH.

29.png

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

30.png

31.png

Я создам случайную строку и напечатаю ее, чтобы увидеть, какая позиция достигает OPCODE, чтобы исправить его.

32.png

33.png

Мы исправляем пакет, который нам нужно передать.

34.png

Я поместил пакету размер 0x10, чтобы увидеть, что после установки правильных опкодов я дойду до уязвимой функции.

35.png

Я вижу, что отправляя программе 0x19 всегда и до тех пор, пока я выполняю RECV в конце после отправки, и соблюдаю длину пакета равную 0x6014, что является первыми двумя байтами размера, без проблем завершилась мной в MEMCPY.

36.png

Здесь программа падает. Я копирую весь стек.

37.png

Если кто-то не поместит recv, программа скопирует 0x3E в буфер, т.е. 0x3E это длина этого пакета, который создаётся, когда завершается соединение. Если мы увидим, что пакет имеет длину строки 0x3E.

"SESSION TERMINATED"

Если мы ищем эту строку, это будет здесь.

38.png

Указатель на эту вторую строку передается как второй аргумент.

39.png

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

40.png

Если VAR_8 мы переименуем P_DESTI то нужно посмотреть откуда он происходит.

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

41.png

И в начале того же самого буфера должно сохраниться значение 0x3E. Оно происходит отсюда. Есть аргумент, который я назвал CONSTANTE.

42.png

На ссылке увидим, что это 1.

43.png

Мы видим, что программа сравнивает значение с 0x13.

44.png

Если оно меньше или равно, то всё хорошо, а если равно 1, то ничего не случиться.

Мы видим, что к ECX прибавляется 1 y сохраняется значение 0x2 в EDX+0x22.

45.png

Есть также еще одна константа, которая выходит из длины строки SESSION TERMINATED.

46.png

К этой длине 0x12 программа добавляет 3 и выполняет SHR, 1

shr eax, 1 ;Signed division by 2

Т.е.

47.png

Что даёт нам значение 0xA.

48.png

Значит в позиции 0x22 есть 2, а в позиции 0x20 0xA.

Программа складывает два значения здесь.

49.png

И затем к результату прибавляется сам результат и число 6.

50.png

Затем.

51.png

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

52.png

Здесь внутри мы знаем, что программа скопировала его в наш буфер, из которого выходит значение, которое проходит через уязвимую функцию.

А сейчас, почему если мы не поставим RECV, программа проходит здесь и все рушит? Вы можете сделать сравнение с и без RECV. Когда мы его убираем RECV программа проходит здесь. Если у программы есть RECV она не проходит и поскольку строка говорит, что сессия завершена, мы можем предположить, что recv поддерживает сессию открытой, и во время сбоя любой......?, Если кто захочет, может проверить это, если это так, используя WIRESHARK, просматривая, если соединение рвется, программа идет сюда, чтобы скопировать 0x3E, а если всё нормально, то она упадет.

Чтобы вы не думали что я вру.

53.png

Я удаляю RECV и запускаю.

54.png

Мы видим, что программа сохраняет здесь 0x3E.

55.png

Мы видим, что я трассирую до функции MEMCPY.

56.png

Мы видим, что 0x3E со строкой SESIÓN TERMINATED.

Мы видим, что на DESTINATION у которого есть наши фрукты, будут перезаписаны, а 0x10 будет перезаписан 0x3E.

57.png

58.png

Если я помещу BPA и помещу BP на уязвимую функцию, программа прочитает это значение.

59.png

Я нажимаю на RUN.

60.png

И здесь все передается, т.е. Мы можем закончить наш пример.

В качестве последнего вопроса меня спросили, есть ли какой-либо способ увидеть с помощью IDA, есть ли какой-либо путь к глобальной переменной, чтобы получить место, где программа копирует данные.

Мы пойдем на функцию откуда было копирование.

61.png

Делая двойной клик на глобальной переменной.

62.png

Я нажимаю на клавишу минус.

63.png

Затем делаю клик в пустой части и выбираю ADD NODE BY NAME.

64.png

Я выбираю SWITCH.

Мы видим, что она осталась там свободной.

65.png

Давайте посмотрим есть ли пути между ними. Их конечно будет много.

Если мы сделаем клик на SWITCH и выберем FIND PATH как BASE DE SOURCE это не функция и она не появляется в списке назначений, но если сделаем наоборот и выберем FIND PATH в BASE DE SOURCE.

66.png

67.png

Этот блок мы можем покрасить через SWITCH→ PATHS.

68.png

Сейчас смотрится лучше.

69.png

Мы хотим получить список.

70.png

71.png

Здесь есть путь от SWITCH к любым опкодам, которые приведут вас к функции A_COPIA_3_0, и приведут вас к доступу к глобальной переменной, которую мы должны увидеть.

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

=======================================================
Автор текста: Рикардо Нарваха - Ricardo Narvaja (@ricnar456)
Перевод на русский с испанского: Яша_Добрый_Хакер(Ростовский фанат Нарвахи).
Перевод специально для форума системного и низкоуровневого программирования — WASM.IN
18.04.2019
Версия 1.0

0 2.091
yashechka

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

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