.. :: ____ _ :: _ ____ _ ____ _ ____ ____\ (________) _/________) _ |_____) \ _____ \\__ _______/ _| /__ | _ \/ /___ / | _ | _ | \ | __// … \\___| \___| \____| \_____| \ … +-------|______//--|_______//---|______//pO!i|_______//-----+ .. ____ _ ____ _ <<:::::::::::::::::::: :: … tEAM-fT … ____| (___\ (_______ ___ ___ ___ ___ ___ ___ ___\ _ _______/__ \\__\\__\\__\\__\\__\\__\ \\___ ___/ | ___// .. … / |__/\___| \ … :: +-----\\______|-------|_______//--+ :: :: TEAM FIFTY THREE TUTORiALS #12 :: Ad-Aware Se Personal - Снимаем диалог инлайном (AsPack 2.11) Автор: Exelios Инструментарий: 1. PEiD 2. Olly Debuger + (ComandBar, OllyDump plugins) Подопытная программа: Ad-Aware Se Personal Build 1.06r1 Статья предназначена для новичков в инлайне, и для новичков в краке вообще.. . Здесь я постараюсь показать две штуки: - как ломал без инлайна, предварительно распаковав; - как я делал инлайн на пакере AsPack, Сравним, что проще и сделаем выводы. Программа выкладывалась на MegaPlus'е 07.2005. Постараюсь объяснить все популярно, так, чтобы после прочтения этой статьи было как можно меньше вопросов, которые, я думаю, несомненно, возникнут. 1. Немного о программе: Программа предназначена для сканирования системы на наличие разнообразных шпионских модулей и вредоносных программ. В принципе, неплохая программка. Хотел сказать, что я не изучал ее досконально на предмет каких либо ограничений, но надоедливое окно, которое вываливается при запуске, должно отсутствовать по определению, дабы поберечь наши с вами нервы... Кстати насчет ограничений, в этом окне фиксируется время испытательного срока. Но как оказалось окончание этого срока ни к чему не приводит, т.е функциональность проги не изменяется ни сколько. Так зачем же нам тогда убивать прогу по дате, просто уберем окно и все. Так ведь? Тем более это проще в нашем случае. Итак, поехали. 2. Распаковка или инлайн: Грузим программу в PEiD и видим, что она запакована ASPack'ом. Теперь у нас с вами есть два пути, которые я опишу ниже. Путь первый - распаковываем, ковыряем и радуемся жизни. Для удобства и уменьшения размера можно запаковать заново, но это уже совсем стремно. Тут ребятки и Аспр инлайнят и не парятся, что мы с вами и ASPack не одолеем, что ли? Путь второй - делаем инлайн, т.е патчим прогу в памяти, не распаковывая. С нашим пакером, путь более простой, да и занимает мало времени... Хотя и предполагает наличие некоторых знаний. Разберем оба пути решения: 2.1 Распаковка и снятие окна: 2.1.1 Распаковка Я лично уважаю Olly, хотя начинал с SoftIce'а, просто он у меня не очень дружил с системой, пришлось отказаться. Ладно, не отвлекаемся... Открываем Олькой подопытный экзешник. На сообщение, которое говорит о том, что в коде паковка/компрессия, и предлагает провести анализ кода отвечаем отрицательно (но это личное дело, просто я считаю после анализа код плохо воспринимается, особенно новичком). Как вы догадались, распаковывать будем ручками…Кому жаль своего времени, могут использовать в этом случае автоматические распаковщики, AsPack Die, например. И так мы стоим на Entry Point, так называемой, точке входа. 00693001 60 PUSHAD 00693002 E8 03000000 CALL Ad-Aware.0069300A 00693007 -E9 EB045D45 JMP 45C634F7 0069300C 55 PUSH EBP 0069300D C3 RETN 0069300E E8 01000000 CALL Ad-Aware.00693014 …………………………………………………………….. …………………………………………………………….. Так вот, именно с этого места и начинается код пакера. В процессе своей работы пакер распаковывает прогу в память, где она и выполняется, будучи уже распакованной. Существует понятие OEP, это наша с вами главная цель, или по другому Оригинальная точка входа. Т.е это нечто иное, как начало распакованной программы. Как бы нам попасть на это начало? В командной строке пишем hr esp-4. Что это значит? И почему так? Объясню как смогу. При запуске программы регистр esp (указатель на верхушку стека) практически всегда равен 12FFC4. Пакер в процессе своей работы производит множество операции со стеком, кладёт, наверно, туда параметры вызываемых функций и т.д. Соответственно, перед переходом на OEP, он должен поправить стек, чтобы при запуске распакованной проги он имел вышеприведенное значение (esp=12FFC4). Т.е командой hr esp-4 мы ставим Hardware breakpoint по адресу 12FFC4-4=12FFC0 на доступ к байту. Это если esp=12FFC4, а если нет ? {Кстати, вот и прога у которой не все по стандартным правилам, и при переходе на OEP esp равен не 12FFC4, а 18FFC4.} Поставили? Жмем F9 - стандартная комбинация Ольки для запуска проги, останавливаемся на поставленном бряке в таком месте: 006933B0 75 08 JNZ SHORT Ad-Aware.006933BA 006933B2 B8 01000000 MOV EAX,1 006933B7 C2 0C00 RETN 0C 006933BA 68 A02B5A00 PUSH Ad-Aware.005A2BA0 006933BF C3 RETN Тут на самом деле все просто. Вообще, если понаблюдать за программами из отладчика, то можно отметить, что при вызове какой-либо функции в стеке запоминается адрес возврата, т.е адрес следующей инструкции, после вызова этой самой функции, например: Стек 77F5166A 005A2BB7 E8 FC45E6FF CALL Ad-Aware.004071B8 4FFDB001 . . . . . . {нажали F7 и попали сюда} Стек . . {тело функции CALL Ad-Aware.004071B8} 5A2BBC . .004071B8 53 PUSH EBX 77F5166A . .004071B9 8BD8 MOV EBX,EAX 4FFDB001 . .004071BB 33C0 XOR EAX,EAX . ……………………………………………… . 005A2BBC 33C0 XOR EAX,EAX <----инcтрукция поле Call 005A2BBE 55 PUSH EBP Затем по Retn происходит переход на адрес, который прежде был положен в стек. Только в этом случае его кладёт пакер командой PUSH 005A2BA0. Кто-то, наверно уже сообразил, что это адрес начала программы. Так и есть. Запишем OEP на листочек или запомним (005A2BA0). Работает RETN и мы на начале распакованной программы. Можем остановиться тут или раньше, на переходе, или на самом RETN. Теперь делаем следующее, снимаем дамп. Программа распакована и находится в памяти, сохраняем ее дампированием… Plugins -> OllyDump ->Dump debugged process. Вываливается окно, в котором должны стоять галочки в местах: Fix raw size…, Rebuild import, и выбран Method2. Жмем Dump и сохраняемся. Теперь нам необходимо восстановить таблицу импорта нашей программы. Делается это по многим причинам. Дело в том что таблица импорта содержит информацию о функциях, используемых программой, и если таблица покалечена (а в нашем дампе это именно так), надо ее вылечить, чтобы прога могла корректно вызвать необходимые функции. Запускаем запакованный экзешник, запускаем ImportReconstructor и в списке процессов выбираем ad-aware.exe. В строке OEP пишем OEP-ImageBase (указан в окне log'а). Т.е получаем 005A2BA0 - 400000=1A2BA0, так? Жмем IAT AutoSearch, для авто-поиска адреса таблицы импорта. Если все прошло до этого нормально, то выскочит сообщение, что адрес скорей всего найден. У меня получилось так: RVA: 001B322C Size:00000B34 RVA (Relative Virtual Address) - виртуальный адрес относительно ImageBase. Нажимаем Get Imports, и видим Yes, в каждой строке. Это хорошо. Значит мы с вами правильно OEP определили, и не криво сдампили… Теперь Fix Dump и сохраняем валидную табличку в наш дамп. Запустим и проверим, то, что было не так давно кучей байт, а теперь рабочий распакованный экзешник ! 2.1.2 Снимаем окно Ну вот, распаковали. Пора и окно снимать. Опять грузим прогу в Ольку. Если быть внимательным, то можно заприметить, что за текст пишется в окне напоминания. Вот за него мы и будем цепляться. Если правой крысой щелкнуть в Ольке в окне кода программы, и выбрать пункты Search for - All referenced text strings, отладчик покажет все текстовые строки, которые использует программа. Найдем же наши! Правой крысой Search for text. Запишите какое-нибудь слово из диалога. Я писал old. Олька находит следующее: ASCII "Your definitions are %1 days old.Would you like to check for updates now?", где в зависимости от текущей даты, в замен % устанавливается некое число. Щелкнем дважды на строке - и мы на ней в окне кода. Не долго думая жмем F2 - ставим бряк, и запускаем прогу. Бряк срабатывает, но мы можем заметить, что помимо этой строки в стек ложатся и другие, видимо программа их вызывает позже, когда необходимо. Если даже предположить, что строка Push'ем закладывается в стек как параметр функции вызова окна... (да что там предполагать - протрасируем немного код). Прошли четыре функции, а окно все не вываливается, значит вызов где-то впереди в коде. Можно конечно трассировать и дальше, пока окно не появиться, но это долго…можете попробовать. Предоставим это Ольке, нажав Ctrl+F8. А прикиньте, сколько времени это было бы вручную ?!. {Хочу сказать, что существует много способов отловки окон, просто этот первый пришел на ум, и оправдал себя} И так окно вывалилось, и ждет нажатия на одну из двух кнопок: 00578EF8 . FF92 E8000000 CALL DWORD PTR DS:[EDX+E8] ; вызов окна 00578EFE . 48 DEC EAX 00578EFF . 75 23 JNZ SHORT 1_.00578F24 Тут JNZ осуществляет либо нет переход на ветку программы, в зависимости от того, какая кнопка была нажата. До этого прога запускалась и работала при нажатии на Cancel, и функциональность при этом не страдала. Поэтому ставим бряк на переход и смотрим: EAX =1, переход осуществляется и прога пошла на запуск. Так…зачем же нам нужна эта процедура ? Занопим CALL DWORD PTR DS:[EDX+E8] и DEC EAX, а переход JNZ SHORT 1_.00578F24 заменим на безусловный. И тогда при запуске программы будет сразу осуществляться прыжок, как будто бы мы нажали Cancel. А чтобы не оставалось мусора занопим и вышестоящую инструкцию (если посмотреть, то по адресу 00578EF6 в EDX ложится некоторое значение из области памяти [EAX], а потом это значение используется для вызова функции CALL….[EDX+E8], и если мы занопим одну лишь функцию, то в EDX это некоторое значение останется, и, возможно, повлияет на работу программы негативном образом, воть так ;) : Было: 00578EF6 . 8B10 MOV EDX,DWORD PTR DS:[EAX] 00578EF8 . FF92 E8000000 CALL DWORD PTR DS:[EDX+E8] 00578EFE . 48 DEC EAX 00578EFF . 75 23 JNZ SHORT 1_.00578F24 Стало: 00578EF6 90 NOP 00578EF7 90 NOP 00578EF8 90 NOP 00578EF9 90 NOP 00578EFA 90 NOP 00578EFB 90 NOP 00578EFC 90 NOP 00578EFD 90 NOP 00578EFE 90 NOP 00578EFF EB 23 JMP SHORT 1_.00578F24 Теперь выделяем это художество и сохраняемся (предварительно создав резервную копию, а то вдруг что): правой крысой - Copy to executable - Selection, правой крысой - Save File. Все теперь готово. Прога работает, и окна нет. 2.2 Инлайн Вы, наверно, заметили сколько было возни в предыдущем методе взлома ? Будем делать инлайн. Самой главное - это запомнить смещения по которым будим патчить. У нас они: с 00578EF6 по 00578EFE - NOP JNZ не патчим, так как eax, при этом на 99,9% не ноль. Тут немного объясню: команда MOV EDX,DWORD PTR DS:[EAX] занимает два байта, ее опкод 8B10h, а NOP - один байт (90h). Поэтому MOV заменяем двумя нопами, также и с другими, тут надо четко учитывать размер команд. Если посмотреть в незапущенной проге, что у нас по адресу, например: 00578EF6, то мы увидим только ADD BYTE PTR DS:[EAX],AL. А нам ведь, по этому адресу патчить, а тут не те инструкции, что были в распакованной программе ! Т.е пакер в дальнейшем, при запуске программы будет распаковывать прогу по этим адресам. И поэтому запустив Ad-Aware из под отладчика и пропатчив байты напрямую (как мы это делали в распакованном файле) не представляется возможным, потому как, по этому адресу будет дописываться код программы, при ее распаковке в процессе запуска и он затрет наш патч. Нам нужно отловить место перехода на OEP, там заменить JNZ SHORT Ad-Aware.006933BA на JMP наш код. А уже наш код, будет менять байты по нужным адресам уже в распакованном к тому времени файле. 006933B0 JMP Ad.00699255 006933B5 ADD BYTE PTR DS:[EAX],AL 006933B7 RETN 0C 006933BA PUSH Ad.005A2BA0 006933BF RETNДля нашего кода нужно место, я его нашел по адресу: 0069925500699255 MOV BYTE PTR DS:[578EF6],90-- 0069925C MOV BYTE PTR DS:[578EF7],90 {минус Mov} 00699263 MOV BYTE PTR DS:[578EF8],90-- 0069926A MOV BYTE PTR DS:[578EF9],90-- 00699271 MOV BYTE PTR DS:[578EFA],90 00699278 MOV BYTE PTR DS:[578EFB],90 {минус Call} 0069927F MOV BYTE PTR DS:[578EFC],90 00699286 MOV BYTE PTR DS:[578EFD],90-- 0069928D MOV BYTE PTR DS:[578EFE],90 {минус dec} 00699294 PUSH Копия_Ad.005A2BA0 {ложим адрес OEP в стек 00699299 RETN и переходим RETN'ом} Сохраняемся… Кстати, полезно будет посмотреть как меняются байты, при выполнении каждой команды, по распатчиваемому адресу. Все, теперь готово к употреблению….