Глава 56
Last updated
Last updated
Не смотря на то, что я хотел перейти к другой теме, появилось много желающих продолжения исследования execryptor, в частности cracmkes b, c и т.д. Посмотрим, сумеем ли мы добраться до максимальной защиты, мы сделаем все возможное, но прежде давайте посмотрим, что есть у b
Запустив программу вне OLLYDBG мы увидим :
Мы знаем, что это b, он должен быть немного сложнее и мы видим, что задействован агрессивный режим, wow, я уже дрожу, хе-хе.
Давайте, прежде всего, посмотрим, выполняется ли программа в OLLYDBG с конфигурацией, использованной нами прежде, с plugin OLLY ADVANCED и остановкой в system breakpoint для удаления BP, размещаемых OLLYDBG для остановки на EP.
Мы в system breakpoint, перейдем в окно b, чтобы удалить breakpoint, размещаемый OLLYDBG автоматически.
Хорошо, я удаляю их и помещаю BREAK ON EXECUTE в первую секцию, как и раньше
Не забываем, что для этого нами используется plugin OLLYBONE.
Хорошо, давайте сделаем RUN
Хорошо, до сих пор различий нет, давайте уберем флажок BREAK ON EXECUTE и остановимся.
Если немного присмотреться, можно заметить, что у нас появилось много threads в сравнении с предыдущим вариантом unpackme, в котором при попадании в OEP их было всего 2.
По-видимому, эти потоки, могут выдать меня, если я сделаю что-то не так.
Мы видим, что если я выполняю RUN, crackme выполняется, но это не означает, что они не будут завершать программу при выполнении скрипта, основываясь на данных времени выполнения участков кода и т.д. Давайте посмотрим, что произойдет, если я отменю все threads, кроме текущего, который отмечен красным цветом.
Я кликнул правой кнопкой мыши и выбрал SUSPEND для всех потоков, кроме главного, выделенного красным цветом, программа выполнится все равно? Давайте посмотрим.
Мы видим, что программа остается RUNNING и ничего не происходит.
Прервав выполнение и посмотрев в call stack, мы увидим, что находимся в WaitForSingleObject, что говорит нам о том, что поток чего-то ждет и пока другие прерваны, он не продолжит свое выполнение.
Хорошо, чтобы найти тот поток, который ждет программа, давайте выберем RESUME для первого потока и сделаем RUN.
Мы видим, что ничего не происходит и программа по-прежнему имеет статус "RUNNING", сейчас, не прерывая программы, давайте снова остановим первый поток и восстановим второй и так до тех пор, пока не найдем есть ли один, который приведет к выполнению программы.
Когда я включаю этот thread, программа выполняется.
Мы видим, что thread - процедура, которая начинается в 270000 на моей машине.
Мы видим, что это просто процедура, находящаяся там
Давайте поместим BPM ON ACCESS в вышеупомянутую секцию
Мы не будем углубляться в исследование работы threads, так как наша задача - ремонт IAT.
Давайте проверим, будет ли выполняться программа с основным и начинающимся на моей машине в 270000 потоками, так как чем меньше будет вмешательства, тем лучше, если бы не было достаточно двух, нам бы пришлось искать 3-ий или другое минимальное число, другая возможность заключается в поимке вызова ExitProcess с помощью BP, так как программа завершает все потоки, перед выходом, и пытаться продолжить с этого места выполнение скрипта.
Давайте посмотрим, будет ли выполняться программа только с этими двумя потоками
Также бывает полезным обратить внимание на приоритет потока, здесь мы видим, что у второго потока приоритет такой же, как и у первого, хотя есть много других с более низким.
Давайте выполним RUN и посмотрим, что произойдет.
Хорошо, эти два threads - необходимый минимум, требуемый unpackme для выполнения.
Я напоминаю, что при решении этих сложных упаковщиков, не нужно запоминать точные шаги или читать туториалы и думать, что все будет идентичным, так что это не будет туториал по execryptor, скорее здесь показано, как можно приспособиться к неблагоприятным условиям, в которые нас поставили и мои рассуждения по мере решения этого пакера. Смысл заключается в том, чтобы читатель отошел от механического выполнения написанного и начал понимать суть.
Возможно, на другой машине мое решение не приводит к выполнению программы и необходима какая-то дополнительная настройка в случаях, подобных этому, где процедура такая длинная и сложная, что OLLYDBG требуется длинный промежуток времени для трассировки и когда мы не можем контролировать все, что делает пакер, могут быть различия, поэтому читатель должен научиться думать сам, и я бы хотел, чтобы вы изучили с этой статьей больше, чем еще один туториал по execryptor, которых и так много.
Важно научиться импровизировать, думать и приспосабливаться к новым ситуациям, так как execryptor может изменяться и не вписываться схему, которая нами показана,
но тот, кто учится искать собственные решения, может двигаться в новых направлениях и решать эти трудности.
Хорошо, так как я заметил во время предыдущих запусков, что, как и в версии "а", первый адрес в IAT переписывается корректным, я попробую вначале тот же метод, что и в предыдущей части, для этого я помещу BPM ON WRITE в вышеупомянутый адрес и запущу трассировку, которая через длительный промежуток времени завершится при срабатывании BPM в этом участке кода. (файл с трассировкой прилагается к статье)
В предыдущем скрипте, чуть повыше в файле трассировки, была инструкция, которая сохраняла в eax верный адрес api и она выполнялась для всех адресов, давайте посмотрим, есть ли она здесь.
Мы видим, что сейчас эта инструкция расположена в 483420, так что теперь нам необходимо помещать HE ON EXECUTION в адрес 483423, который указывает на следующую инструкцию.
Конечный скрипт предыдущей части был
Мы помним, что в предыдущей части адрес, где происходило чтение api, был
0047691C Main MOV EAX,DWORD PTR SS:[EBP-C] ; EAX=77DA6BF0
0047691F Main MOV ESP,EBP ; ESP=0012FFB0
в то время как сейчас
00483420 > 8B45 F4 MOV EAX,DWORD PTR SS:[EBP-C] ; kernel32.GetVersion
00483423 . |8BE5 MOV ESP,EBP
так что в скрипте мы должны заменить 47691f, который был адресом, где скрипт помещал HE ON EXECUTION, для получения верного адреса в EAX, на 483423 и скрипт примет вид
Здесь мы меняем адреса, выделенные красным цветом, константы, выделенные синим, а именно начало и конец IAT а также константа 50000000, необходимая для определения, является ли адрес IAT переадресацией или нет, остались прежними, также мы помним о том, что необходимо вручную поставить точку останова в ZwTerminateProcess для того, чтобы каждый раз, когда происходит попытка закрытия программы, мы могли продолжить работу.
Хорошо, давайте перезапустим olly, снова переместимся в OEP, нужно не забыть снять BREAK ON EXECUTE и галочки в DEBUGGING OPTIONS - EXCEPTIONS - MEMORY ACCESS VIOLATION, как в прошлый раз.
Сейчас необходимо не забыть остановить все threads, кроме 2, которые являются необходимыми, прежде чем выполнять скрипт.
Мы видим, что скрипт хорошо исправляет таблицу, но начиная с определенного адреса, он сохраняет неверное значение.
Первый адрес, который вычисляется неверно - это 46099с, давайте посмотрим, какая запись соответствует ему в логе.
Там мы видим, что начиная с этого адреса, порождается исключение ошибка доступа на чтение адреса 880045, которого раньше не было и которое происходит дальше каждый раз.
Если я изменю скрипт таким образом, чтобы при возникновении исключения он переходил к следующему адресу, ситуация не улучшается и исключение по-прежнему происходит в том же адресе, с той лишь разницей, что теперь не происходит записи в таблицу.
Что же тут происходит? Неужели вариант b содержит дополнительные хитрости? Давайте посмотрим, где может быть ошибка.
Раньше при обнаружении ошибки происходила попытка закрытия программы, но теперь по логу видно, что не происходит вызовов ZwTerminateProcess, я провоцировал исключение для того, чтобы можно попасть и вернуться из ZWTerminateProcess, но теперь этого не происходит, может всему виной галочка в memory access exception? Давайте посмотрим, что будет, если я ее поставлю и запущу скрипт снова.
AHHHHHHHHHHHH, сейчас это функционирует как раньше, на каждом адресе порождается исключение из-за ошибки, которую я спровоцировал, и мы попадаем в ZwTerminateProcess и сейчас таблица исправляется, ошибка состояла в том, что не было отмечено memory access.
То есть нужно поставить галочку для правильного функционирования скрипта, давайте посмотрим на таблицу.
Скрипт принял вид :
(прим. пер. у меня это не заработало, мой вариант в файле 56_1.osc)
и нужно помнить, что необходимо вручную установить HE on EXECUTION по адресу ZwTerminateProcess перед запуском, поставить галочку в MEMORY ACCESS EXCEPTION и отменять избыточные threads.
Я прибываю в OEP, снимаю BREAK ON EXECUTE, снова обращаю Ваше внимание на то, что должны быть отмечены все галочки исключений, устанавливаю HE ZwTerminateProcess и запускаю скрипт.
Исправление успешно завершается.
Сейчас я делаю дамп с помощью OLLYDMP и открываю IMP REC.
Я вижу, что все адреса исправлены
Сейчас я должен исправить TLS, мы открываем dumpeado в OLLY и в header ищем
и изменяем на
а затем сохраняем изменения
Теперь программа функционирует правильно, хе-хе, в следующей части мы встретимся с c, еще один этап пути пройден.
До встречи в статье 57
[C] Рикардо Нарваха, 10.11.06