В этом разделе мы познакомимся с макросами ввода-вывода, разберем несколько более сложных примеров и посмотрим на листинги.
Структура ассемблерной программы
Посмотрим еще раз на программу из предыдущего раздела:
include console.inc .code Start: mov ecx, 5 again: outstrln ‘Hello World’ dec ecx jnz again exit end Start
Разберем структуру исходного текста этой программы:
- Строка include console.inc подключает макросы, которые мы будем использовать в этом курсе. О макросах мы поговорим чуть ниже.
- Строка .code открывает секцию кода.
- Следующие четыре строки содержат собственно код нашей программы. Отдельно стоит упомянуть метку Start , которая соответствует точке входа в нашу программу — мы можем разместить ее и не в начале кода. outstrln — это вызов макроса для вывода строки на стандартный поток вывода. Этот макрос определен в файле console.inc .
- exit — это также макрос из console.inc , который осуществляет системный вызов, завершающий работу программы.
- Наконец, директива end Start сообщает ассемблеру, что исходный текст программы закончился, и одновременно информирует его, какую метку ( Start ) нужно использовать в качестве точки входа.
Макросы
Для написания простейших программ на языке ассемблера нам потребуется не так много возможностей языка. Умения работать с командами пересылки данных, арифметическими вычислениями и переходами вполне достаточно. Помимо этого, потребуется представление о структуре ассемблерной программы и директивах резервирования памяти.
ВИРУС на Ассемблере | Как программно отключить монитор?
Кроме этого, не хватает только возможностей ввода-вывода. Поскольку для организации ввода-вывода (а также, например, для завершения работы программы) требуется обращаться к операционной системе, мы не можем (пока) сделать этого самостоятельно — нам потребуется материал, который в этом курсе разбирается позднее.
В качестве врéменной меры мы будем пользоваться ограниченным набором макросов, определенных в файле console.inc . Этот файл разработан для нашего курса, найти его можно в каталоге include внутри каталога MASM (например, C:masm32include ).
Макросы будут подробно разбираться далее в конце этого курса, и в дальнейшем мы познакомимся с тем, как устроен console.inc . На текущем этапе нам нужно знать о них следующее: макросы раскрываются в некоторый код языка ассемблера (возможно, в 2-3 машинные команды, а возможно, и в десятки и даже сотни).
Макросы ввода-вывода
Кратко рассмотрим минимальный набор макросов, которыми будем пользоваться в ближайшее время:
- inchar , outchar — ввод и вывод символов; единственный операнд — код символа, который может быть регистром или памятью размерности 8, а в случае вывода еще и непосредственным операндом.
- inint , outint , outword — ввод и вывод целых чисел; outword выводит число как беззнаковое, outint — как знаковое. Размерность операнда может быть 8, 16 или 32.
- outstr «text» можно использовать для вывода текста.
- newline выводит символы возврата каретки и перевода строки.
- flush очищает буфер ввода.
- Наконец, макрос exit завершает работу программы.
Ниже приведена шпаргалка по макросам:
#1 Первая программа на ассемблере MASM
outchar op1 ; r/m/i 8 вывод символа inchar op1 ; r/m 8 ввод символа outint op1 ; r/m/i 8/16/32 вывод целого с/з outword op1 ; r/m/i 8/16/32 вывод целого б/з inint op1 ; r/m 8/16/32 ввод целого outstr «text» ; вывод строки newline ; вывод символов CR LF flush ; очистка буфера ввода exit ; завершение работы программы
Пример программы: числа Фибоначчи
Попробуем написать простую, но законченную программу. Наша программа (назовем ее fib ) будет запрашивать у пользователя номер n и вычислять n-е число Фибоначчи.
Наша программа не будет использовать никаких переменных в памяти, обходясь одними регистрами.
Запросим у пользователя число n и поместим его в регистр EDX:
outstr «enter n: » inint edx ; F_n to calculate
Проинициализируем рабочие регистры. Текущее число Фиббоначчи Fk будем хранить на EAX, предыдущее Fk — на EBX. Само текущее k будем держать в ECX:
mov eax, 1 ; F_2=F_k mov ebx, eax ; F_1 mov ecx, 2 ; k=2
Если нас просят вычислить F1 или F2, ответ (единица) у нас уже готов, прыгнем вперед на метку result (команда jbe , jump if below or equal, переходит на указанную метку, если беззнаковое сравнение на меньше или равно было истинным, т. е. EDX ≤ 2):
cmp edx, 2 ; F_1 or F_2? we already have the answer jbe result
В основном цикле вычисления мы будем складывать два предыдущих члена последовательности до тех пор, пока не доберемся до искомого n-го члена. Если сложение вызовет перенос, прыгнем на метку overflow , чтобы сообщить об ошибке:
nx: xchg ebx, eax ; ebx
Если всё хорошо, выведем результат (EAX):
result: outstr «F_» outword edx outstr » highlighter-rouge»>overflow: outstr «The result exceeds 2^32» fin: exit end Start
Программа целиком
include console.inc .code Start: outstr «enter n: » inint edx ; F_n to calculate mov eax, 1 ; F_2=F_k mov ebx, eax ; F_1 mov ecx, 2 ; k=2 cmp edx, 2 ; F_1 or F_2? we already have the answer jbe result nx: xchg ebx, eax ; ebx
Поместим текст программы в файл fib.asm в рабочем каталоге, после чего соберем и запустим ее при помощи mkr :
C:work>mkr fib.asm Assembling: fib.asm enter n: 10 F_10 = 55
Генерация листинга
Чтобы узнать, как выглядит машинный код, в который была оттранслирована наша программа, мы можем запросить построение файла листинга, который будет содержать, в числе различной дополнительной информации, адреса команд и машинный код.
Для генерации листинга используется аргумент /Fl (регистр символов важен). Получим листинг программы fib :
C:work>ml /c /coff /Fl fib.asm Microsoft (R) Macro Assembler Version 6.14.8444 Copyright (C) Microsoft Corp 1981-1997. All rights reserved. Assembling: fib.asm
Файл листинга будет называться fib.lst . Откроем его в текстовом редакторе.
Листинг состоит из двух страниц — собственно листинга и таблиц макросов, процедур, структур и т. д. Остановимся подробнее на листинге:
include console.inc C .NOLIST C .LIST C C C ;include masm32.inc C C includelib masm32.lib C includelib user32.lib C includelib kernel32.lib C includelib msvcrt.lib C includelib io_proc.lib C C 00000000 .code 00000000 Start: outstr «enter n: » inint edx ; F_n to calculate 0000003C B8 00000001 mov eax, 1 ; F_2=F_k 00000041 8B D8 mov ebx, eax ; F_1 00000043 B9 00000002 mov ecx, 2 ; k=2 00000048 83 FA 02 cmp edx, 2 ; F_1 or F_2? we already have the answer 0000004B 76 0E jbe result 0000004D 93 nx: xchg ebx, eax ; ebx
Листинг состоит из трех колонок: первая содержит адреса (точнее, смещения в секции), вторая — сгенерированный машинный код и третья — соответствующие строчки исходного кода программы.
Примечание. Обратите внимание, что вызовам макросов никакого машинного кода в листинге не соответствует. Это происходит потому, что в console.inc генерация листинга для макросов подавлена. Ее можно снова включить директивой .LISTMACRO .
По листингу сразу видно, что команда mov формата «регистр — константа» занимает 5 байт (1 байт на код операции и обозначение формата и регистра-приемника, плюс 4 байта на сам непосредственный операнд), а команда формата «регистр — регистр» — только 2 байта.
Адреса в первой колонке «прыгают» от 0 к 3C потому, что макросы outstr и inint раскрываются в некоторое количество машинных команд, которые попросту не отражены в листинге.
Если обратить внимание на команду jbe result , то видно, что переход указан относительно, т. е. «вперед на 8 байт». Если прибавить 8 к адресу следующей команды, 4Dh , то получится 55h — адрес метки result .
Листинг для секции данных
Если в нашей программе будет присутствовать секция данных, то для нее также будет сгенерирован листинг, по которому будет видно содержимое памяти, которое будет отведено под каждую из наших переменных.
Например, пусть секция данных выглядит вот так:
.data B db 15 W dw 15 D dd 15 B2 db -2 D2 dd -2 Pr db «ABCD» X db ‘A’ X2 db 41h
Тогда соответствующий фрагмент листинга будет таким:
00000019 .data 00000019 0F B db 15 0000001A 000F W dw 15 0000001C 0000000F D dd 15 00000020 FE B2 db -2 00000021 FFFFFFFE D2 dd -2 00000025 41 42 43 44 Pr db «ABCD» 00000029 41 X db ‘A’ 0000002A 41 X2 db 41h
Из этого примера хорошо видно, к чему приводит указание одинаковых начальных значений для переменных разных размерностей, а также то, что символы представляются их ASCII-кодами.
Источник: warmland.ru
Использование макросов в MASM на примере создания окна
В далеком 2001-ом году я проводил много времени за изучением ассемблера под Win32. Тогда после долгих мучений с написанием одного и того же кода по сотне раз я взялся написать для себя небольшую библиотеку макросов. В итоге удалось достаточно серьезно облегчить себе судьбу и уменьшить необходимость повторять огромные полотенца кода, при необходимости написать простейшую программу с одним окном.
Недавно наткнулся на те проекты и решил выложить некоторые из них, может кому пригодится…
Состав проекта
Итак приступим. Проект, прикрепленный внизу, имеет следующую структуру.
Macros | Каталог с макросами, используемыми в приложении |
Macros.Inc | Здесь находятся основные макросы, которые нужны при написании любой Win32 программы. Здесь макросы для выделения памяти, облегчения включения файлов, макросы для определения данных и проч. |
Window.Mac | Макросы, которые облегчают создание окон |
Status.Mac | Макросы для создания и использования статус строк |
Menu.Mac | Макросы для создания и использования меню |
Quake.Bmp | Изображение, которое будет загружено и отображено в окне программы |
Scull.Ico | Иконка изображения (просто черепок) |
Rsrc.rc | Файл определения ресурсов |
Window.Asm | Основной файл программы |
Window.Exe | Откомпилированная программа |
WndExample.Asm | В данном файле находится исходный код для обработки сообщений идущих к окну «Example» нашей программы |
При запуске Window.Exe отображаемое окно будет выглядеть следующим образом:
Простейшая программа, без окна
Первой строкой здесь включение основных макросов, далее идет макрос Start, который создает начало программы и подставляет информацию о модели памяти, об используемом процессоре и проч. Далее идет макрос Uses он включает необходимую библиотеку в программу. В данном случае мы будем использовать kernel32.dll так как именно она содержит в себе используемую нами функцию завершения процесса ExitProcess.
Далее следует блок кода указанный с помощью .code, в котором находится основная процедура программы. По факту сама процедура может называться как угодно и название WinMain я дал ей просто от балды. Главное, чтобы в конце файла была строка End
Эта программа не несет никакой функциональной нагрузки, поэтому после запуска она ничего не будет делать — просто завершит свою работу. Теперь исходный код программы, приведенной в архиве:
Инициализируют переменные /инстанс приложения, иконка, курсор, кисть для отрисовки окна/. Здесь используется приятный макрос Result. Этот макрос выполняет указанный вызов API с переданными параметрами и возвращает содержимое регистра EAX, который служит для возврата результатов функции. Если бы не было данного макроса, то каждая строка разбивалась на подобный код :
invoke GetModuleHandle, NULL mov hInstance, eax
Файл с обработчиками событий
Основная процедура в приведенном проекте находится в конце файла и выглядит так:
В принципе все, что связано с этими событиями можно посмотреть в MSDN и исходниках, в этом нет ничего сложного и в данном описании я не буду включать.
Компиляция программы
Для компиляции необходим пакет masm32 (можно найти здесь) После установки желательно внести путь до каталога masm32bin в переменную окружения Path и отредактировать файл masm32/bin/build.bat исправив вызов компилятора ml и линкера, чтобы добавить пути библиотек и включаемых файлов и не приходилось постоянно данные пути прописывать в коде.
Так в вызов ML.Exe нужно добавить еще один параметр /IF:masm32include — вместо F:masm32 вам нужно указать путь, куда установился пакет masm32 у вас. А в два вызова линкера Link.exe нужно добавить путь к библиотекам с помощью параметра /LIBPATH:F:masm32lib. Опять же путь замените на тот, который соответствует вашему.
Далее, в каталоге с проектом даем две команды: bres (bres.bat производит компиляцию файла ресурсов rsrc.rc в текущем каталоге) и следом за ним build window (build.bat — производит компиляцию и линковку проекта).
Проекты переложил на GitHub
- ассемблер
- макросы
- пользовательский интерфейс
Источник: habr.com
Примеры программ на masm32
>> Рассмотрим пример создания загрузчика(loader) для ASProtect
>> Universal Loader для Total Commander(оригинальный код by Nabu)
>> Еще один простой пример
[iNT R0]
Умение программирования есть одно из лучших качеств хорошего крякера, ибо все, что делается руками, можно автоматизировать. Нашел способ распаковать хитрый паковщик/протектор — можно написать распаковщик. Главное вооружиться MSDN или Win32 SDK(поставляется, например, с Delphi или с C++Builder) и уметь кодить на чем-нибудь. отличным от Басика и просто Поцкаля.
Мы же будем использовать MASM32(для его скачивания нет лучше сайта, чем www.wasm.ru). Макроассемблер крут и удобен. W32ASM — pure and simple 😉 Тем более при компиляции получаются проги ОЧЕНЬ маленького размера, что хорошо крякеру, который что-то релизит в инет. Итак, начнем.
[PART I] ASProtect Loader
Очень много сказано о защите ASProtect, особенно о его распаковке, долгой и мудежной, в большинстве случаев — с подлянами и засадами. Всё новые приемы обнаружения отладчика. Новые его версии уже в win9x хрен снимешь. Да, есть конечно Stripper, но я часто встречал случаи, когда распакованный файл не запускался, хотя версия аспра стриппером поддерживалась.
Но очень простой способ прокатывает почти на всех прогах запакованных аспром — это создание загрузчика. Нет, аспр проверяет при запуске целостность кода, но что если патчить память, когда проверка уже произошла и Protection Error 15 не покажется? Вот. И для этого давайте напишим лоадер, который при желании можно заделать под просто лоадер для непакованных прог. Для этого будем использовать функции отладки. Используемые функции и их аргументы:
BOOL CreateProcess( LPCTSTR lpApplicationName, // имя проги LPTSTR lpCommandLine, // CommandLine LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCTSTR lpCurrentDirectory, LPSTARTUPINFO lpStartupInfo, //Инфа о стартапе LPPROCESS_INFORMATION lpProcessInformation //Инфа о процессе );
В принципе, нужное я обозначил. Если хотите узнать, какие значения может принимать lpProcessAttributes, lpThreadAttributes, dwCreationFlags и другие, то сходите в msdn.com или пошарьте в Win32 SDK, да и вообще в любом справочнике по Win API.
BOOL WriteProcessMemory( HANDLE hProcess, // Это процесс, созданный по CreateProcess LPVOID lpBaseAddress, // Виртуальный адрес, по которому надо произвести запись LPVOID lpBuffer, // Это байты, которые надо записать DWORD nSize, // Номер байтов для записи LPDWORD lpNumberOfBytesWritten // Кол-во байтов для записи 🙂 );
Здесь не должно возникнуть вопросов.
BOOL ReadProcessMemory( HANDLE hProcess, LPCVOID lpBaseAddress, LPVOID lpBuffer, DWORD nSize, LPDWORD lpNumberOfBytesRead );
Да это тоже самое, только здесь не запись в память, а чтение.
Ну вот, теперь запускаем QuickEditor(QEDITOR.EXE в папке MASM32). Пишем туда наш код
======= bEGIN oF mpatch.asm =======.486 .model flat, stdcalloption casemap :none include masm32includewindows.inc include masm32includemasm32.inc include masm32includeuser32.inc include masm32includekernel32.inc include masm32includeshell32.inc includelib masm32libmasm32.lib includelib masm32libuser32.lib includelib masm32libkernel32.lib includelib masm32libshell32.lib; include — необходимый минимум для нашей проги.data App db «DzSoft PHP Editor»,0 ; Ну эт я над прогой такой издевался 🙂 Err1 db «Program not found :(«,0 ; Обломов prog db «DzPhpEd.exe»,0 ; Имя проги bufwr DWORD 90h ; Мне нужно байт 75 поменять на NOP(90) va DWORD 579C03h ; Это первый адрес, по которому надо произвести запись va2 DWORD 579C04h ; А это второй.data? bufr dw ? ; Байт, в который производится чтение pinfo PROCESS_INFORMATION <> ; Это Инфа о процессе sinfo STARTUPINFO <> ; Это инфа о запуске n DWORD ? ; Кол-во байтов.codestart: ; Оффицильное начало invoke CreateProcess,addr prog,NULL,NULL,NULL,FALSE,CREATE_NEW_CONSOLE OR NORMAL_PRIORITY_CLASS,NULL,NULL,addr sinfo,addr pinfo; Создаем процесс.. CREATE_NEW_CONSOLE OR NORMAL_PRIORITY_CLASS; для того, чтобы запускаемая прога не сворачивалась..IF eax == 0 ; Если EAX(результат) равен 0(прога не запустилась) invoke MessageBox,NULL,addr Err1,addr App,MB_OK ; Выдаем сообщение invoke ExitProcess,0 ; И выходим :).ENDIF.WHILE TRUE ; Это цикл. Вот за такие high-level ; макросы я очень MASM люблю :)invoke ReadProcessMemory,pinfo.hProcess,va,addr bufr,1,n ; Читаем память.IF eax != 0 ; Если все ОК.IF bufr != 00h ; И байт под адресу va(579C03h) не ; равен 00h(прога распакована уже), то. invoke Sleep,300 ; Слипаем глаза, пока аспр проверяет целостность кодаinvoke SuspendThread,addr pinfo.hThread ; Тормозим нашу прогуinvoke WriteProcessMemory,pinfo.hProcess,va,addr bufwr,1,n ; Пишем куда надо NOPinvoke WriteProcessMemory,pinfo.hProcess,va2,addr bufwr,1,n ; И сюда тоже NOPinvoke ResumeThread,addr pinfo.hThread ; Отправляем прогу дальше invoke CloseHandle,pinfo.hThread ; Сворачиваем мокрухуinvoke ExitProcess,0 ; Уходим.ENDIF.ENDIF.ENDWend start ; Оффициальный конец======= eND oF mpatch.asm =======
ну че? и все! Теперь Build All и получаем лоадер в 2,5 Кб. Этот размер до того маленький, что даже UPX говорит: «Зачем сжимать? Тут и сжимать нечего!» :). Похожую прогу писал — = ALEX = — , но у него вся эта тема была на делфи с его лишним весом 🙂 тем более я делфу не знаю(и не уютно в ней чувствую себя), знаю только C и ASM(эти языки — рай для программиста).
Чтоб делать просто лоадер(без всяких там Sleep и цикл м проверкой на распакованность), просто уберите эти строки :). То есть вам надо будет только CreateProcess, SuspendThread, WriteProcessMemory и т.д.
[PART II] Universal Total Commander Loader
Универсальный кряк для крутого файлового менеджера Total Commander. В самой проге применен алгоритм шифровки кода. Если надо — копайтесь, а мы пойдем путем шаровика 🙂 Разработчики хорошо постарались, закриптовав прогу, но допустили погрешнсть — надо сначала показать наг, а потом МейнСкрин(основное окно), а у них НАГ блокиует MainScreen, а поэтому его легко убрать.
Берем маленькую прогу WindowMan с y0da.cjb.net и зажав CTRL направляем на наг-скрин Total Commander мышу. Класс зовется TNASTYNAGSCREEN, запомним. Теперь таким же образом смотрим на главное окно, оно зовется TTOTAL_CMD, учтем.
Все, это достаточно, чтоб написать лоадер, который убирает наг автоматически. Подобную прогу уже представлял Nabu. Но там был C, а мы напишем на ассемблере и немного доработаем:
======= bEGiN oF tcmdcrk.asm ======= .486 .model flat, stdcall option casemap :none include masm32includewindows.inc include masm32includemasm32.inc include masm32includeuser32.inc include masm32includekernel32.inc include masm32includeshell32.inc includelib masm32libmasm32.lib includelib masm32libuser32.lib includelib masm32libkernel32.lib includelib masm32libshell32.lib .dataWND1 HWND ?WND2 HWND ?WNDNAME1 db «TNASTYNAGSCREEN»,0 ; ага! вот где имя класса нага пригодилось!WNDNAME2 db «TTOTAL_CMD»,0 ; имя класса главного окнаCAPTION db «Total Commander 5.5 — bi0w0rM»,0 ; ну ето просто :)EXENAME db «totalcmd.exe»,0 ; Имя проги .codestart:INVOKE WinExec, addr EXENAME, SW_SHOWNORMAL ; Запускаем.WHILE TRUE ; Пусть прога бьется в цикле, когда надо — выйдем по ExitProcessINVOKE FindWindow,addr WNDNAME2,NULL ; ищем окно TTOTALCMD MOV WND2,EAX ; Кладем результат в WND2.IF EAX != 0 ; Если окно нашлос-такиINVOKE FindWindow,addr WNDNAME1,NULL ; То изем еще одно окно — НАГMOV WND1,EAX ; Ложим результатINVOKE ShowWindow,WND1,SW_HIDE ; Убираем наг НАФИКINVOKE EnableWindow,WND2,TRUE ; Енейблим главное окноINVOKE SetForegroundWindow,WND2 ; И делаем его сразу активнымINVOKE SetWindowText,WND2,addr CAPTION ; Ну и небольшой прикол:) который не проходит :((INVOKE ExitProcess,0 ; Уходим. .ENDIF.ENDWend start======= eND oF tcmdcrk.asm =======
У Nabu был прикол со Sleep.
У нас же лоадер быстрее, так как бьется в цикле, пока не не создастся окно. Если он его находит — убивает наг и енейблит окно. Спасибо тебе, Nabu! Так бы я не решился такого написать!
[ЕЩЕ!]
Еще недавно попросили меня сделать кейген для крякмиса фантома(FaNt0m’s Crackme #4). Я разобрался в алгоритме генерации, но что-то лениво очень было писать 🙂 Я решил — опять пойдем другим путем 🙂 в результате — тот же кейген!
В опщем посмотрев в листинге w32dasm я увидел, что сам ключ лежит по адресу 403284. Можно было бы использовать функции отладки, ставить бряки, пробиваясь в цикле. Зачем? можно сделать все проще. Итак, привожу проверку ключа:
===== Начало Листинга =====:00401205 6800010000 push 00000100:0040120A 6884304000 push 00403084* Possible Reference to Dialog: MAINDIALOG, CONTROL_ID:03E8, «» |:0040120F 68E8030000 push 000003E8:00401214 FF7508 push [ebp+08]* Reference To: USER32.GetDlgItemTextA, Ord:0102h |:00401217 E862010000 Call 0040137E:0040121C 6800010000 push 00000100:00401221 6884314000 push 00403184* Possible Reference to Dialog: MAINDIALOG, CONTROL_ID:03E9, «» |:00401226 68E9030000 push 000003E9:0040122B FF7508 push [ebp+08]* Reference To: USER32.GetDlgItemTextA, Ord:0102h |:0040122E E84B010000 Call 0040137E:00401233 FF7508 push [ebp+08]:00401236 E8BE000000 call 004012F9:0040123B 83F800 cmp eax, 00000000:0040123E 7415 je 00401255:00401240 6A40 push 00000040* Possible StringData Ref from Data Obj ->»Check Serial» |:00401242 6829304000 push 00403029* Possible StringData Ref from Data Obj ->»You got it! Congrats! :)»; . ; В процедуре 004012F9 явно происходит проверка, зайдем в нее::004012F9 55 push ebp:004012FA 8BEC mov ebp, esp:004012FC 56 push esi:004012FD 57 push edi:004012FE 8D3584304000 lea esi, dword ptr [00403084]:00401304 8D3D84324000 lea edi, dword ptr [00403284]:0040130A 33C0 xor eax, eax:0040130C 33C9 xor ecx, ecx:0040130E B31A mov bl, 1A* Referenced by a (U)nconditional or (C)onditional Jump at Address:|:00401328(U)|:00401310 803E00 cmp byte ptr [esi], 00:00401313 7415 je 0040132A:00401315 8A06 mov al, byte ptr [esi]:00401317 02C1 add al, cl:00401319 32C1 xor al, cl:0040131B F6F3 div bl:0040131D 66C1E808 shr ax, 08:00401321 0441 add al, 41:00401323 8807 mov byte ptr [edi], al:00401325 47 inc edi:00401326 46 inc esi:00401327 41 inc ecx:00401328 EBE6 jmp 00401310* Referenced by a (U)nconditional or (C)onditional Jump at Address:|:00401313(C)|:0040132A C60700 mov byte ptr [edi], 00:0040132D 33C0 xor eax, eax:0040132F 83F900 cmp ecx, 00000000:00401332 741A je 0040134E:00401334 6884324000 push 00403284:00401339 6884314000 push 00403184* Reference To: KERNEL32.lstrcmpA, Ord:02D6h |:0040133E E8A1000000 Call 004013E4 ; Ну уж кда проще — вызов strcmp. Сравнивает строки на похожесть:00401343 83F800 cmp eax, 00000000 ; Если не одинаковы, то жопа:00401346 7404 je 0040134C ; и джамп. :00401348 33C0 xor eax, eax:0040134A EB02 jmp 0040134E* Referenced by a (U)nconditional or (C)onditional Jump at Address:|:00401346(C)|:0040134C 8BC1 mov eax, ecx* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:|:00401332(C), :0040134A(U)|:0040134E 5F pop edi:0040134F 5E pop esi:00401350 C9 leave:00401351 C20400 ret 0004.
Перед началом вызова strcmp были записаны два параметра: 00403184 и 00403284. По достоверным данным, которые мне дали SoftICE и OllyDbg — в 00403284 лежит правильный ключ. Что делать теперь? Посмотрим на вызов обламывающего окна:
:00401255 6A30 push 00000030* Possible StringData Ref from Data Obj ->»Check Serial» |:00401257 6829304000 push 00403029* Possible StringData Ref from Data Obj ->»Wrong Serial! Keep trying, you’ll » ->»get it!» |:0040125C 6836304000 push 00403036:00401261 6A00 push 00000000* Reference To: USER32.MessageBoxA, Ord:01BBh |:00401263 E834010000 Call 0040139C===== Конец Листинга =====
Короче, вместо push 00403036, мы ставим push 00403284 и тогда вместо появления надписи Wrong Serial нам покажецца наш ключ! :)) Какие байты менять? было 6836304000, а станет 6884324000. Но мы раз кейгенщики, то давайте сделаем, чтобы байты патчились на лету! Вот прога:
======= bEgIN oF loader.asm ======= .486 .model flat, stdcall option casemap :none include masm32includewindows.inc include masm32includemasm32.inc include masm32includeuser32.inc include masm32includekernel32.inc include masm32includeshell32.inc includelib masm32libmasm32.lib includelib masm32libuser32.lib includelib masm32libkernel32.lib includelib masm32libshell32.lib .dataExe db «CRACKME4.EXE»,0 ; ПрогаApp db «bi0w0rM’z loader»,0 ; Понты :)Error1 db «Could not create process :((«,0 ; Сообщение, если не удалось запустить Error2 db «Fucking Version :((«,0 ; Если это вовсе не наш крякмис, ; а соффсем другая прога .data?Sinfo STARTUPINFO <> ; Надо для запускаPinfo PROCESS_INFORMATION <> ; Надо для запускаWByte DWORD ? ; Байт для записиRByte DWORD ? ; Байт для чтенияAdr DWORD ? ; Адрес для патчаn DWORD ? ; Кол-во байтофф .codestart:invoke CreateProcess,addr Exe,NULL,NULL,NULL,FALSE,NORMAL_PRIORITY_CLASS,NULL,NULL,addr Sinfo,addr PinfoCMP EAX,0JNZ PATCHINVOKE MessageBox,NULL,addr Error1,addr App,MB_ICONERRORINVOKE ExitProcess,0PATCH:MOV Adr, 0040125DhMOV WByte,84hCALL PATCHERMOV Adr, 0040125EhMOV WByte,32hCALL PATCHERMOV Adr, 0040125FhMOV WByte,40hCALL PATCHERinvoke CloseHandle,Pinfo.hThreadINVOKE ExitProcess,0FUCK:INVOKE MessageBox,NULL,addr Error2,addr App,MB_ICONERRORPATCHER PROCINVOKE ReadProcessMemory,Pinfo.hProcess,Adr,addr RByte,1,nINVOKE WriteProcessMemory,Pinfo.hProcess,Adr,addr WByte,1,nRETPATCHER ENDPend start======= eND oF loader.asm =======
Теперь скомпилируем лоадер и запустим его в папке с крякмисом. Введем имя и кей от балды. Во! Появляется мессага с нашим ключом.
Возможно, что в скором времени я напишу подобную статью, только уже об непосредственно отладке, бряках, трейсинге и т.д. Может даже напишем простенький распакоффщик для UPX. Но это будет потом, а пока на этом я прощаюсь.
07.10.2008 22:34
19.10.2007 23:18
Источник: ahteam.org