Русские документы
Ежедневные компьютерные новости RSS rusdoc.ru  Найти :
Новости
Последние поступления
Книжный магазин
  Hardware:
Видеоустройства
Системные платы
Процессоры
Мобильные устройства
Аудиосистема
Охлаждение системы
Накопители информации
КПК и ноутбуки
Телефоны и связь
Периферия
Система
Сети
Разные устройства
 
  Programming:
Web-разработка
Языки программирования
Технологии и теория
Разработка игр
Программная инженерия
 
  Software:
Операционные системы
Windows 7
Базы данных
Обзоры программ
Графика и дизайн
   
  Life:
Компьютерная жизнь
Разные материалы
   
Партнеры
Публикация
Правовая информация
Реклама на сайте
Обратная связь
Экспорт в RSS Экспорт в RSS2.0
    Читать в Яндекс.Ленте



Взлом компонентов Delphi

Раздел: Programming / Assembler @ 13.11.2007 | Ключевые слова: взлом дельфи delphi компоненты dcu components версия для печати

Автор: Павлов А.Ю.
Источник: Realcoding.net

Описана работа с файлами dcu результатом которой является превращение платных компонентов в бесплатныеЭтот документ описывает некоторые аспекты работы с компонентами Дельфи, а именно работу с уже скомпилированным кодом компонента в файле 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 - поиск в нескольких файлах и поиск с произвольными символами. В общем методика полностью аналогична.

 

    На последок несколько советов:
  1. Поиск нужного участка кода можно выполнить найдя текст выводимый компонентом (определив его адрес в модуле и найдя ссылку на этот код - это скорее относится к OllyDbg)
  2. может возникнуть необходимость перепрыгнуть некоторый участок кода - когда нечего изменить(так было в NativeExcel который писал в ячейку A1:A1 инфу о том что это демо). Просто надо ассемблировать следующий код(tasm)
    jmp short	cs:6 + 2   ; 6 - это выход на след инструкцию после jmp - 2 сколько байт надо перепрыгнуть
    команда занимает 2 байта с опкодом EBXX - где хх - сколько байт надо перепрыгнуть
  3. . Если нашли в dcu нужный участок - не торопитесь сразу менять его - таких участков может быть нескотлько - замена не того может привети к ошибкам
  4. После того как изменения сохранены - проект надо закрыть и открыть ну и естественно перекомпилять :) - тогда изменения вступят в силу.
  5. Я ни в коем случае не призываю ломать все напропалую - всетаки разработчик тоже человек :), потративший на создание некоторое время и обоснованно считающий себя в праве получить некоторой вознаграждение за свой труд. В тоже время легкость с которой можно переделать практически любой компонент подкупает :). Так что как поступать - ваше дело.
Ну и для тех кто знает ассемблер - пример небольшой програмы-крякалки, ее задача заключается как раз в пропатчивании нужных файлов(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

	

	; начанаем непосредственно крякать :)

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

Автор: Intser
http://www.intser.fatal.ru/

Это интересно:








версия для печатиРаспечатать статью


Вернуться в раздел: Programming / Assembler


Реклама:
Читать наc на:

Add to Google
Читать в Яндекс.Ленте






Rambler's Top100
© Copyright 1998-2012 Александр Томов. All rights reserved.