Наверное, прочитав название этой статьи Вы подумали «Да чё это с тем парнем, неужели он пишет свои проги в OllyDbg !!!», но если серьезно то бывает и такое!:), попадается какая-то прога которую ну очень нужно «подправить», вот тут то OllyDbg самое то!!!
Эту статью я написал для новичков, независимо кракеров или программистов, так как ее цель дать необходимую информацию для встраивания своего кода в exe, dll файлы. Первоначально я ориентировался на кракеров, но в процессе написания решил дать больше общей информации, по той простой причине что ее очень не хватает.
Дабы не растягивать сию статью применять эту технику я собираюсь на собственной проге (кракми), продемонстрировав таким образом в одной статье ряд тех приемов которыми я часто пользуюсь.
Итак, скоренько я набросал кракмис с наг-скрином, и проверкой количества оставшихся запусков в реестре.
1. Снимаем ограничение количества запусков.
Кракмис хранит количество запусков в ветви реестра HKEY_CURRENT_USERAndyMovuns типа integer и когда такой отсутствует то прога его создает думая что она запущена впервые(часто встречающиеся решение), иначе при каждом запуске значение этого параметра уменьшается на 1, когда значения этого параметра меньше 1 то прога просто отказывается запускаться, значит нужно до того как программой будет осуществляться проверка этого параметра просто удалить его.
Вот отрывок листинга из Regmon.exe в подтверждение:
OpenKey HKCUAndyMov SUCCESS Key: 0xE1785188
QueryValue HKCUAndyMovuns SUCCESS 0x1E
QueryValue HKCUAndyMovuns SUCCESS 0x1E
SetValue HKCUAndyMovuns SUCCESS 0x1D
CloseKey HKCUAndyMov SUCCESS Key: 0xE1785188
Итак, теперь нам нужно найти немного незадействованного места в.ЕХЕ ф-ле программы для размещения своего кода, одно из таких мест находится начиная с адреса 00452518 и до 004525F0(как видно ниже, из отрывка дизассемблерного листинга значения байтов в этих адресах = 00, и обычно такое встречается в конце секций, то есть если например в конце секции кода вы увидите нули то это и есть пространство для размещения вашего кода, проверим, откройте файл calc.exe в PE editore LordPE, нажмите на кнопку [sections], в окне что появилось выделите секцию [.text]- это и есть секция кода и в контекстном меню пункт [hex edit section...], в конце выделения(то есть секции(у меня 00012AED)) вы увидите байты 00) :
00452518. 0000 ADD BYTE PTR DS:[EAX],AL
0045251A. 0000 ADD BYTE PTR DS:[EAX],AL
0045251C. 0000 ADD BYTE PTR DS:[EAX],AL
0045251E. 0000 ADD BYTE PTR DS:[EAX],AL
00452520. 0000 ADD BYTE PTR DS:[EAX],AL
00452522. 0000 ADD BYTE PTR DS:[EAX],AL
00452524. 0000 ADD BYTE PTR DS:[EAX],AL
…… ...
004525F0. 0000 ADD BYTE PTR DS:[EAX],AL
Удалить нужный ключ реестра можно с помощью АПИ функции RegDeleteKey:
LONG RegDeleteKey(
HKEY hKey, // хэндл откр. ключа
LPCTSTR lpSubKey // адрес строки с именем ключа
);
Delphi пример: RegDeleteKey(HKEY_CURRENT_USER, AndyMov);
Но проблема в том что подопытная прога не импортирует такой функции!!!
Конечно можно узнать адрес необходимой АПИ функции например с помощью команды EXP имя функции SoftIcea, и потом сделать джамп или кол на этот адрес, но адреса АПИ ф-ций могут быть не одинаковые даже в двух одинаковых ОС но разных билдов, тоесть если у Вас на WinXP proff RU прога работает это еще не значит что прога будет работать на всех WinXP, что уж говорить о других осях! Потому придется каждый раз узнавать адрес нужной функции динамически программным путем(добавлять нужную АПИ автоматически с помощью разных инструментов я не хотел так как это просто, добавлять импорт вручную тяжеловато, а с помощью АПИ как раз то что нужно). И сделать это можно с помощью АПИ функции GetProcAddress которая в качестве результата возвращает адрес нужной функции, или NULL в случае неудачи, вот ее прототип:
FARPROC GetProcAddress(
HMODULE hModule, // хэндл модуля DLL
LPCSTR lpProcName // имя функции (RegDeleteKey)
);
Где взять хэндл модуля DLL? Конечно у функции GetModuleHandle :)
У этой функции всего один параметр, смотрим ее прототип:
HMODULE GetModuleHandle(
LPCTSTR lpModuleName // адрес с именем модуля хэндл которого
); // требуется узнать
Теперь у нас есть вся необходимая информация для успешного осуществления задуманного!
Вот пример дельфи кода который возвращает адрес ф-ции RegDeleteKey:
GetProcAddress(GetModuleHandleA(AdvApi32.dll), RegDeleteKeyA);
Теперь остается только запрограммировать этот код в OllyDbg.
Итак, грузим кракмис в олли, ставим курсор по адресу 00452518 (думаю вы без особых проблем отыщите немного места для своего кода в любом екзешнике, иначе может пока не стоит читать далее), делаем дабл-клик по этой строке листинга дизассемблера(но не на поле адресов иль автоанализа), и в окне что появилось начинаем вводить такой код(в конце каждой строки жмем ENTER):
Push 004525D8 // адрес строки AdvApi32.dll
Call GetModuleHandleA // получаем в еах хэндл AdvApi32.dll
Push 004525E5 // адрес строки RegDeleteKeyA
Push EAX // хэндл модуля AdvApi32.dll
Call GetProcAddress // получаем в еах адрес вызова RegDeleteKeyA
Push 004525F3 // адрес строки AndyMov(удаляемый ключ)
Push 80000001 // HKEY_CURRENT_USER
Call EAX // Удалить ключ :)
Mov EAX, 004522F0 // команда спертая с ОЕР, на месте этой // команды я поставил переходник по // которому передается управление с ОЕР на // мой код: JMP адрес_начала_моего_кода.
Jmp 004524DB // передача управления на ОЕП,
// программа продолжает нормальную работу
Вот и все! Теперь осталось только разместить текстовые строки в .EXE нашего кракми. Это можно сделать многими способами даже в OllyDbg, но я предпочитаю такой:
Помещаем курсор по адресу 00452518 (для Delphi прог почти всегда немного ниже ОЕР), должны быть такие строки:
00452518. 0000 ADD BYTE PTR DS:[EAX],AL
0045251A. 0000 ADD BYTE PTR DS:[EAX],AL
0045251C. 0000 ADD BYTE PTR DS:[EAX],AL
0045251E. 0000 ADD BYTE PTR DS:[EAX],AL
00452520. 0000 ADD BYTE PTR DS:[EAX],AL
Как видно из этого листинга все пространство в этом промежутке адресов инициализировано нулями. В контекстном меню этой строки дизассемблера выбираем команду View -> Executable file, в окне дампа что появилось с помощью контекстного меню даем команду Hex -> Hex/ASCII(16 bytes), после чего данные в окне отображаются будто в обычном HEX редакторе, выделяете необходимую область для размещения данных, и давим Ctrl+E (как альтернативу используем команду Binary -> Edit контекстного меню), теперь можно ввести всю необходимую инфу, после чего сохранить модифицированный .EXE файл (при закрытии окна дампа олли спросит, нужно ли сохранять изменения вот это отладчик! :).
Запускаем прогу… ОК ключ удаляет, ограничение количества запусков снято, но остался надоедливый наг-скрин :( ...
2. Снимаем наг-скрин.
Для снятия надоедливого окна наг-скрина можно воспользоваться разнообразными АПИ функциями, это дело вкуса, я здесь просто отправлю окну сообщение WM_CLOSE что заставит окно-получатель исчезнуть, конечно можно действовать и более радикальными методами например уничтожить надоедливое окошко, но в данном случае мы обойдемся без этого(безопаснее просто скрыть окно чем уничтожать его, тем более последнее связано с рядом трудностей и потому не всегда возможно), тем более что после прочтения п.1 этой статьи Вы имеете достаточно информации чтобы сделать это по-другому как сами захотите.
Итак, чтобы отослать наг-скрину сообщение WM_CLOSE которое его спрячет мы воспользуемся функцией SendMessageA вот ее прототип:
LRESULT SendMessage(
HWND hWnd, // хэндл окна-получателя
UINT Msg, // отсылаемое сообщение (WM_CLOSE)
WPARAM wParam, // первый параметр сообщения (0 или 1)
LPARAM lParam // второй параметр сообщения (0 или 1)
);
Остается узнать хэндл(дескриптор) окна которое надо скрыть, то есть нашего нага. Используя АПИ FindWindow мы без проблем вычислим наш наг-скрин:
HWND FindWindow(
LPCTSTR lpClassName, // указатель на имя класса окна
LPCTSTR lpWindowName // указатель на текст заголовка окна
);
Значит план действий такой:
— получаем хэндл наг-скрина
— отправляем окну сообщение WM_CLOSE
Как вводить код ассемблера в OllyDbg вы уже знаете(нет? Читайте сначала), потому повторять не буду и сразу привожу ассемблерный листинг:
Push 0 // заголовок окна — NULL
Push offset Wnd_Class_Name // 1-й параметр класс искомого окна
Call FindWindowA // получить хэндл окна Wnd_Class_Name
Push 0 // 2-й параметр (не используется )
Push 0 // 1-й параметр (не используется )
Push 10 // константа WM_CLOSE
Push EAX // хэндл окна для отправки сообщения
Call SendMessageA // отправляем сообщения WM_CLOSE
Mov EAX, 0045251C // эмуляция спертой команды (вместо // этой команды на ее оригинальном месте я поместил JMP на начало своего кода, теперь выполняю эту команду и передаю управление на следующую за ней, будто ничего не бывало)
Jmp XXXXXXXX // передача управления программе
Вот и все! Хочу сказать что труднее чем записать этот код было отыскать нужное место для него, так как выполнять эго нужно после создания окна наг-скрина иначе никакого эффекта не будет(наш код просто не найдет нужного окна).
Напоследок
Программировать код на низком уровне не легко, особенно трудны первые шаги, надеюсь эта статья поможет Вам сделать этот первый шаг в мир машинного кода. Я старался написать как можно проще, и дать наиболее необходимую информацию, имея которую можно самостоятельно продолжить эксперименты с кодом, хорошим заданием для вас теперь будет самостоятельно добавить в.ехе windows калькулятора(calc.exe, notepad.exe… выбирайте по вкусу) код который выводил бы MessageBox, с вопросом запустить calc.exe или отменить запуск, после нажатия ОК соответственно запуская калькулятор, при нажатии CANCEL закрывая прогу, разумеется, вам будет нужен M$ SDK.
Наиболее часто работоспособность кода нарушается из за несогласованности стека ВНИМАТЕЛЬНО следите за тем чтобы ваш код извлекал из стека ровно столько параметров сколько помещал. Если вами будет затерта какая-то команда для передачи управления вашему коду, то настоятельно рекомендую восстанавливать ее при передачи управления, следите за этим и я уверен что большой части проблем с функционированием кода у вас не будет. Если места для размещения своего кода наидти не удастся то свой код можно вынести в отдельную секцию(создать новую секцию можно в том же PETools или LordPE, там есть еще много полезного для «перепрограммирования» .exe :).
2 комментария