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

Дата публикации 22 ноя 2017 | Редактировалось 27 ноя 2017
Осталось решить незаконченное упражнение IDA1.EXE.

1.png

Функция основана на EBP как предыдущие упражнения. Разница заключается в том, что этот пример скомпилирован с помощью DEVC++, который имеет особый способ компиляции вызовов API, отличный от обычного способа и это может вызвать головокружение, у тех, кто никогда такого не видел.

Хорошо, "VAMOS POR PARTES", как сказал Джек. Первое, что мы видим - это функция MAIN. Если она не появляется, Вы также можете перейти к важной функции, просто посмотрев на строки.

2.png

Сделаем двойной щелчок по строке “You are a winner man je” и мы попадём на этот адрес:

3.png

Я помещаю курсор мышки над стрелкой перекрёстной ссылки. Мы можем видеть куда ведёт эта перекрёстная ссылка.

4.png

Но лучше, конечно, нажать CTRL + X. Так мы попадём туда, где находится данный код.

5.png

Переходим в этот код, щелкая по этой ссылке.

6.png

Я меняю в зеленый цвет блок кода, который является ХОРОШИМ СООБЩЕНИЕМ. Нам нужно попасть в него.

Мы видим, что перед ним идёт сравнение переменной VAR_C с константой 0x51525354.

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

7.png

Я могу изменить это представление на буквы QRST, которые являются символами ASCII этого HEX значения.

Мы также можем видеть, что компилятор не использует CANARY защиту, потому что в начале функции программа должна считать переменную из секции DATA и XORить эту переменную с помощью регистра EBP и сохранить её чуть выше STORED EBP в стек, а также, считать её снова, непосредственно перед выходом из функции, чтобы вызвать CALL, который проверит это значение переменной. Ничего из этого не происходит здесь. Если мы посмотрим статический анализ стека, сделав двойной щелчок на любой переменной.

8.png

Мы видим, что единственное, что есть в стеке, чуть выше STORED EBP, это переменная VAR_C, которая сравнивается со строкой QRST, чтобы идти к хорошему сообщению, что исключает, что это переменная CANARY, так как в этом случае это проверка, которая принадлежит исходному коду программы. CANARY не подмешивается к решениям исходного кода программы. Это что-то добавленное самим компилятором, внешнее по отношению к исходному коду и это не защита.

Мы можем переименовать эту переменную, чтобы не путать её с CANARY. Назовём её как VAR_DECISION.

9.png

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

Те, кто смотрит на этот код впервые, обратят внимание, что существуют переменные и аргументы связанные с EBP, но есть и другие, которые отсчитываются от ESP.

10.png

Весь этот начальный код, добавлен компилятором, чтобы установить ESP чуть выше переменных и локальных буферов. После исполнения SUB ESP, 0B8 программа подготовлена к этому. Хотя программа никогда не изменяет намного больше памяти чем выравнять и округлить, мы могли бы делать математические расчёты. Но если мы не хотим осложнять себе жизнь, мы можем отладить программу, чтобы увидеть какое значение осталось в ESP, чтобы закончить всё это и начать с оригинального кода функции.

Тот, кто захочет отладить это место, может сделать это, но у нас есть другая помощь от IDA, которая очень полезна. Это расчёт отклонения ESP в стеке начиная с самого начала стека функции, что принимается за нуль.

11.png

Если посмотрим на код сейчас, после установки этой опции.

12.png

Мы видим влияние каждой инструкции на стек начиная с нуля, что является началом стека. После выполнения инструкции PUSH EBP, стек уменьшается на 4, поэтому у второй строки справа написано 004.

Вторая инструкция - это MOV EBP, ESP, которая не изменяет стек, потому что это только одинокая инструкция MOV и поэтому регистр ESP не меняется, а изменяется только регистр EBP.

13.png

Вот почему третья строка имеет то же самое значение 004, потому что инструкция не изменила значение ESP.

Давайте запомним, что ESP и EBP остаются одинаковыми и EBP, начиная отсюда, будет ссылкой отстающей на 4 байта от начала ESP.

Следующая строка вычитает значение 0xB8 из ESP, поэтому ESP будет равен 0xBC от начала отсчёта в стеке и поскольку EBP был равен 4, разница между EBP и ESP будет только 0xB8 байт.

14.png

Мы видим, что потом расстояние не меняется, даже при вызове функций __ALLOCA и ___MAIN, которые добавлены компилятором. Поэтому, мы можем заключить, что всё это не влияёт ни на что. Расстояние между EBP и ESP всё также равно 0xB8 и это пространство для локальных переменных и буферов.

15.png

Здесь уже начинается код самой функции и расстояние от ESP до начала стека осталось равным 0xBC и 0xB8 - это область, зарезервированная для локальных переменных и буферов.

Поскольку переменная VAR_9C является временной переменной, созданной компилятором и не используется больше, то мы переименуем её в TEMP.

16.png

Ниже переменной TEMP у нас есть буфер. Я делаю правый щелчок и выбираю – ARRAY. Мы видим, что размер буфера равен 140 байт в десятичной системе, так как каждый элемента равен 1 байт, поэтому и размер буфера равен 140 байт в десятичной системе.

17.png

18.png

Если бы нам удалось переполнить буфер, скопировав в него больше 140 байт, он бы имел уязвимость типа BUFFER OVERFLOW, эксплуатируя которую, можно было бы перезаписать переменную VAR_DECISION и если бы могли писать дальше вниз, нам удалось бы дойти до STORED EBP и RETURN и перезаписать их, в зависимости от того, сколько байт мы скопировали.

Давайте продолжим реверсить. Самая высокая точка компиляции - это способ, как Вы передаёте аргументы в функции. Вместо того, чтобы использовать PUSH для сохранения аргументов в стек, сохраняйте их непосредственно с помощью инструкции MOV. Мы увидим скоро это пример.

Здесь всё становится ясно. В этом случае, PRINTF имеет единственный аргумент, который является адресом строки “You are a winner je” и больше не имеет никаких других аргументов.

19.png

Мы видим, что программа сохраняет этот адрес, так как она использует слово СМЕЩЕНИЕ впереди, и сохраняет адрес в стек, но куда? Обозначения не особо нам помогают, но если мы сделаем правый щелчок, мы увидим несколько альтернативных обозначений.

20.png

Если мы изменим представление на этот пункт.

21.png

Мы видим, что то, что действительно происходит, состоит в том, что адрес строки помещается в содержимое ESP (самое верхнее положение стека), чтобы использовать его как аргумент. Другими словами, это программа вместо того, чтобы исполнить PUSH на вершине стека, помещает аргументы в положение стека с помощью инструкции MOV и логически PUSH изменяет значение ESP, в то время как инструкция MOV – нет. Это можно увидеть по значению BC, которое расположено непосредственно перед функцией.

22.png

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

23.png

Мы видим, что первый PRINTF имеет 3 аргумента, потому что он заменяет форматную строку в строке “buf : %08x cookie : %08x\n”. Для двух верхних аргументов, будет так.

24.png

Первый аргумент - это адрес переменной VAR_DECISION, который получен с помощью инструкции LEA. Инструкция помещает адрес в EAX и сохраняет его в содержимое ESP + 8.

Второй аргумент - это адрес переменного буфера, который получен также с помощью LEA. Инструкция помещает его в EAX и сохраняет адрес в содержимое ESP+4 как следующий аргумент. Третий аргумент сохраняет адрес в содержимое ESP и это будет адресом строки. В нашем случае, это строка с форматом.

Если Вы запустите программу вне IDA, мы увидим, что программа печатает в консоли адреса обоих переменных, так как программа заменяет исходную строку на форматную, на HEX значения обоих адресов, потому что используется последовательность %x, которая является преобразованием вывода строки в HEX представление.

25.png

26.png

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

27.png

Здесь также программа передаёт адрес буфера, в который будут поступать символы с клавиатуры как аргумент, в содержимое ESP

Так что мы знаем, что если я напишу например 140 символов A и затем символы TSQR, так как они должны идти наоборот из-за режима LITTLE ENDIAN, программа должна показать мне хорошее сообщение, так как мы будем перезаписывать переменную VAR_DECISION значением QRST, которая находится чуть ниже буфера. Давайте сначала сделаем всё это вручную, перед тем как сделать скрипт.

28.png

Я печатаю строку в IDA, и копирую её в буфер обмена, и вставляю её здесь.

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAATSRQ

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

29.png

Скрипт очень простой. Он также совпадает с предыдущим. В нашем случае он не имеет двух потоков ввода для STDIN, а имеет только один.

from subprocess import *
p = Popen([r'C:\Users\ricna\Desktop\New folder (6)\IDA1.exe', 'f'], stdout=PIPE, stdin=PIPE, stderr=STDOUT)

print "ATACHEA EL DEBUGGER Y APRETA ENTER\n"
raw_input()

primera="A" *140 + "TSRQ\n"
p.stdin.write(primera)

testresult = p.communicate()[0]

print primera
print(testresult)


30.png

Здесь Вы видите результат. Многие не смогли бы это сделать из-за способа передачи аргументов. Но сейчас будет проще сделать упражнение №2, так как оно очень похожее и скомпилировано таким же образом, и Вы уже знаете про этот трюк.

Следующее упражнение называется IDA2.EXE.

До встрече в 24-той главе.


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

9 7.289
yashechka

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

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

Комментарии


      1. yashechka 30 ноя 2017
        Так что решайте, мы идём дальше до конца, и потом возвращаемся назад, и исправляем все мои ошибки и Рикардо или начинаем всё заново.
      2. yashechka 30 ноя 2017
        Прям хочется всё бросить и начать сначала и довести до такого уровня как последние переводы:hunter:
      3. yashechka 30 ноя 2017
        Aoizora Сегодня, в 00:36
        И все переведено так убого и коряво. Прям лицо вирусной сцены, состоящей из недоучек.​
        ===
        Aoizora Сегодня, в 00:35
        >Здесь AX помещается в содержимое EBX
        >
        [EBX]
        Складывается впечатление, что автор не понимает, что он переводит, и просто генерирует небрежный машинный перевод. Еще и какую-то статью про шеллкоды писать вздумал. Ты русский и английский язык для начала выучи. Наверно, еще и без работы сидишь, потому что C++ не осилил.​
        ===
        Aoizora Вчера, в 19:31
        >AH это 5-я и 6-я цифра и AL две последние цифры (8 бит каждая)
        >(8 бит каждая)
        Что за чушь? AL содержит один байт. В байте 8 бит. Две 16-ричных цифры составляют байт, поэтому каждая цифра занимает 4 бита.
        Нельзя же писать такую откровенную дезинформацию. Как вообще можно браться за перевод статей о реверсе, не имея фундаментальных знаний?​
      4. yashechka 30 ноя 2017
        m1nu78p Спасибо.
        Мне тоже нравится, самое интересное уже близко, но Вы видели, что было написано?
      5. yashechka 28 ноя 2017
        8570 Спасибо:thank_you2::thank_you2::thank_you2:
      6. jkmjkmjkm 28 ноя 2017
      7. yashechka 3 дек 2017
        :thank_you2::thank_you2::thank_you2:
        DzenGURU нравится это.
      8. m1nu78p 30 ноя 2017
        Спасибо, все интересней становиться :cools:
        yashechka нравится это.