Пятница, 19.04.2024, 01:56 Приветствую вас Гость | Группа "Гости" 
Меню сайта

Категории раздела
Вирусология [40]
Статьи о вирусах
Системные [1]
Работа с системой
Примеры [45]
Приёмы, функции, процедуры
Ceти [1]
Работа с интернет
Шуточные программы [5]
Пишем шуточные программки
Остальное [6]
Всё что не вошло

Популярные статьи

Недавние темы

Опрос
Какой версией Delphi пользуетесь?
Всего ответов: 774

Главная » Статьи » Delphi » Остальное

Delphi 6-7 разбор *.dcu
Ни для кого не секрет, что многие хорошие компоненты, предоставляющие удобную функциональность, часто имеют один общий существенный недостаток - за них надо платить. Обычно это выражается в различных предупреждающих надписях и предложениях покупки. Здесь будут рассмотрены варианты организации подобной защиты и способы ее преодоления. 

Для работы вам понадобится: отладчик(желательно SoftIce, но можно обойтись и без него, или хотя бы OllyDebugger - очень хороший отладчик пользовательского уровня), hex - редактор(я использую WinHex - очень мощная программа), минимальное понимание winapi и общей работы Windows, а также хотя бы представление о языке программирования ассемблер(не помешает какой-либо асемблер - я лично предпочитаю tasm). 

Итак, приступим. Случай первый, симптомы : предупреждающее сообщение при запуске программы в случае незапущенного IDE. Ясно что компонент при запуске программы проверяет наличие запущенного IDE - если нет -получаем сюрприз. Самый распростроненный способ - проверка наличия в системе окон определенного класса, которые создает среда разработки. Этот поиск осуществляется функцией FindWindow, смотрим ее описание в Win SDK: 


HWND FindWindow(
LPCTSTR lpClassName, // pointer to class name
LPCTSTR lpWindowName // pointer to window name
);

lpClassName - указатель на имя класса, например TAppBuilder
lpWindowName - указатель на имя окна - обычно пустое, т.е поиск всех окон указанного класса

В случае успеха - хэндл найденного окна, иначе 0; 
Методика работы: 
Создаем приложение с интересующим нас компонентом - подключенным dcu. 
Запускаем SoftIce и ставим бряк на FindWindow(кто не знает - bpx FindWindowA ну или FindWindowExA или смотрите exp FindWindow) - айс запустится в момент вызова этой функции. 
Запускаем программу. 
Попадаем в айс - проматываем F10 до выхода из FindWindow и узнаем откуда была вызвана эта функция (адрес возврата конечно можно вытащить и из стека). Что мы видим в отладчике(компонент NativeExcel): 
push 00h // 0 - пустой указатель на имя окна
push 0005F6498 // узакатель на класс окна 
call USER32!FindWindowA
mov ebx,eax // сохранение результата
push 00h
push 005F64A8
call USER32!FindWindowA
mov esi,eax
push 00h
push 005F64B8
call USER32!FindWindowA
mov edi,eax
push 00h
push 5F64CC
call USER32!FindWindowA
test ebx,ebx // проверка результата - видно если окна нет - прыгаем куда-то
jz 005E136D // как раз на сообщение
test esi,esi
jz 005E136D
test edi,edi
jz 005E136D
test eax,eax
jz 005E136D
jmp куда-то на выход // надо добраться сюдa

По адресам передаваемым в функцию FindWindow в даном случае находятся TApplication, TAlignPalette, TPropertyInspector, TAppBuilder. Кстати важное замечание - практически все функции WinApi возвращают результат в регистр eax - т.е. в нашем случае в eax будет содержаться хэндл окна или 0. Например в Ems QuickPDF полностью аналогичный код - правда проверок меньше - и успокаивается в случае если хотя-бы одно окно есть в системе. 
Так что с этим делать? Ответ прост - самое правильное найти этот код в файле dcu используя hex-редактор и немного его поправить. Если используется WinHex - просто забиваем код в шаблон и ищем(кстати call выглядит как E800000000 - нули это адрес который проставит PE-загрузчик при загрузке файла). 
Заменять инструкцию call нельзя - так как загрузчик пропатчивая адрес вызова снесет все что было вами туда записано - в результатеполучится случайная инструкция, обычно приводящая к ошибке памяти. Самое простое решение в данном случае - заменить 2-х байтовую команду test на например 2 однобайтовые команды inc - кто не знает - эта команда увеличивает операнд на 1, вот некоторые опкоды - вы можете сами посмотреть их создав процедуру или программу на ассемблере и посмотрев ее в отладчике: 

inc eax 40h
inc ebx 43h
inc esi 46h 
inc edi 47h

Кому не в лом, может посмотреть правила формирования команд процессора. Итак, найдя в dcu нужный код, меняем инструкцию 84С0 на 4040 в итоге получаем: - теперь компонент думает что ide запущено несмотря ни на что. 


Таким образом, разобран первый случай, переходим ко второму. Симптомы: c первого взгляда те же - но сообщение появляется вне зависимотсти от наличия в системе ide. В чем дело - случайно догадываемся что скорее всего дело в отладчике, т.е. программа проверяет наличие отладчика - и если его нет - мы имеем плачевный результат. Как это можно определить - смотрим sdk: 


The IsDebuggerPresent function indicates whether the calling process is running under 
the context of a debugger. 
BOOL IsDebuggerPresent(VOID)

Эта функция возвращает 0 если текущий процесс запущен не из под отладчика и не 0 в противном случае. Далее технология подобна описанной выше. Этот способ представлен в пакете AlphaControls - большой набор очень красивых контролов. Правда разработчики этого пакета поступили хитро, напихав проверок в разный молули (защита проявляется последовательно при добавлении новых компонентов в проект и проверки находятся в файлах sStyleSimple.dcu, sCommonData.dcu, sStypePassive.dcu) - тут проявилось очень важное свойство WinHex - поиск в нескольких файлах и поиск с произвольными символами. В общем методика полностью аналогична. 


На последок несколько советов: 
Поиск нужного участка кода можно выполнить, найдя текст, выводимый компонентом (определив его адрес в модуле и найдя ссылку на этот код - это скорее относится к OllyDbg) 
может возникнуть необходимость перепрыгнуть некоторый участок кода - когда нечего изменить(так было в NativeExcel который писал в ячейку A1:A1 инфу о том, что это демо). Просто надо ассемблировать следующий код(tasm) 
jmp short cs:6 + 2 ; 6 - это выход на след инструкцию после jmp - 2 сколько байт надо перепрыгнуть

команда занимает 2 байта с опкодом EBXX - где хх - сколько байт надо перепрыгнуть 
. Если нашли в dcu нужный участок - не торопитесь сразу менять его - таких участков может быть несколько - замена не того может привести к ошибкам!
После того, как изменения сохранены, проект надо закрыть и открыть заново, ну и естественно перекомпилять smile - тогда изменения вступят в силу. 
Я ни в коем случае не призываю ломать все напропалую - все таки разработчик тоже человек :), потративший на создание некоторое время и обоснованно считающий себя в праве получить некоторой вознаграждение за свой труд. В тоже время легкость, с которой можно переделать практически любой компонент, подкупает :). Так что как поступать - ваше дело. 

Ну и для тех кто знает ассемблер - пример небольшой програмы-крякалки, ее задача заключается как раз в пропатчивании нужных файлов(tasm, все константы взяты из файла Windows.pas), выполнена в виде консольного приложения. Можно посмотреть что такое файловый мэппинг если вы не в курсе: 

.386 
includelib import32.lib 
include const32.inc
extern ExitProcess: proc 
extern GetStdHandle: proc
extern WriteConsoleA: proc 
extern CreateFileA: proc
extern CreateFileMappingA: proc
extern MapViewOfFile: proc
extern CloseHandle: proc
extern UnmapViewOfFile: proc 
extern MessageBoxA: proc 
extern FormatMessageA: proc
extern GetLastError: proc 
extern LocalFree: proc
.model flat
.data 
SHandle dd ? 
data db '1234343',0Ah,0Dh,0 
Result dd ?
w32_f_d _WIN32_FIND_DATAA <0,0,0,0,0,0,0,0,0,0> 
old_str db 0C0h,084h
new_str db 040h,040h

m_title db 'title',0

FileHandle dd ?
FileMap dd ?
MemBase dd ? 

FileName db 'data.txt',0
my_map_name db 'my_map11',0 

buf_str dd ? 

Enter db 0Ah,0Dh,00h ; 
file1 db 'dlg1.res',0 ;
file2 db 'dll.bat',0 ;
file3 db 'dll.asm',0 ;
file_names dd offset file1, offset file2,offset file3 ; имена файлов которые надо патчить
file_lengths dd 08,07,07 ; длины имен - для вывода на консоль
file_offsets dd 00h,00h,00h ; смещения нужного кода
num dd 2
.code
Start: 
WriteC macro Text,len
push 0
push offset Result
push len
push Text
push SHandle
call WriteConsoleA

push 0
push offset Result
push dword ptr 2
push offset Enter
push SHandle
call WriteConsoleA
endm
; получаем консоль
push STD_OUTPUT_HANDLE
call GetStdHandle
mov SHandle,eax 
test eax,eax
jz on_error

; начанаем непосредственно крякать smile
start_crack: 
mov ecx,num
xor ebx,ebx
push ebx
push FILE_ATTRIBUTE_NORMAL
push OPEN_EXISTING 
push ebx
inc ebx
push ebx
xor ebx,ebx
push 80000000h or 40000000h
push dword ptr file_names[ecx*4]
call CreateFileA ; открываем файл
inc eax
test eax,eax
jz on_error ;если ошибка - выходим
dec eax
mov FileHandle,eax 



xor ebx,ebx 
;------------ создаем карту файла
push offset my_map_name
push ebx
push ebx 
push PAGE_READWRITE
push ebx
push eax
call CreateFileMappingA
test eax,eax ;если ошибка - на выход
jz on_error
mov FileMap,eax 

xor ebx,ebx

;------------ мэппируем файл в адресное пространство нашего процесса
push ebx
push ebx
push ebx
push 00000002h
push eax
call MapViewOfFile
test eax,eax ;если ошибка - на выход 
jz on_error
mov MemBase,eax 

mov ecx,num
mov edi,eax
add edi,dword ptr file_offsets[ecx] 
mov esi,offset old_str
push edi
cmpsw ; сравниваем байты по смещению с шаблоном 
jne on_incorrect_file ; если что-то не то - выходим

pop edi 
mov esi,offset new_str
movsw 
jmp on_free_resource 

on_incorrect_file:
pop edi

on_free_resource: ; освобождаем ресурсы
push MemBase
call UnmapViewOfFile

push FileMap
call CloseHandle

push FileHandle
call CloseHandle

;=== inc

mov ecx,num
WriteC file_names[ecx*4],file_lengths[ecx*4]


dec num
jns start_crack


jmp on_close
on_error: ; сообщение о ошибке через FormatMessage 
call GetLastError 
push 0
push 100h
push offset buf_str
push 0
push eax
push FORMAT_MESSAGE_FROM_HMODULE
push FORMAT_MESSAGE_ALLOCATE_BUFFER or FORMAT_MESSAGE_FROM_SYSTEM 
call FormatMessageA 
test eax,eax
jz on_close
push 0
push offset m_title
push buf_str
push 0
call MessageBoxA
push buf_str
call LocalFree

on_close:
push 00h
call ExitProcess
end Start

Категория: Остальное | Добавил: dolphin (21.03.2009)
Просмотров: 5836 | Рейтинг: 5.0/1

Всего комментариев: 0
avatar
Профиль


Логин:
Пароль:

Поиск

Наша кнопка
Вирусология, взгляд из Delphi

Статистика
Top.Mail.Ru Яндекс.Метрика Счетчик тИЦ и PR
Статистика материалов
Файлов: 454
Форум: 1165/8116
Коментариев: 768
Новостей: 29

Статистика пользователей
Всего: 331
За неделю: 2
Вчера: 1
Сегодня: 0
Всего онлайн: 1
Гостей: 1
Пользователей: 0

delphicode.ru © 2008 - 2024 Хостинг от uCoz