Статьи‎ > ‎

Препарируем quartz.dll

Автор: Beketata  

Предысторию, почему мне пришлось дизассемблировать quartz, изложить в двух словах довольно сложно. Отчасти это было сделано ради того, чтобы можно было "подебажить" свой фильтр, отчасти ради спортивного интереса, т.к. подобный опыт у меня до этого уже был, но такую большую по объему dll я осилил впервые. Если и есть смысл что либо прокомментарить, так это сам проект, чем я сейчас и займусь:

1. Дизассемблирование производилось с помощью IdaPro 5.0.0.879
http://cracklab.ru/download.php?action=get&n=MjE1. Проект "quartz_orig.idb" для Ida лежит в исходниках, т.к. с ним приходится постоянно работать, что то исправлять и добавлять и регулярно туда подглядывать.

Основная проблема после дизассемблирования это разделение данных и кода, восстановление секций SEH, а так же, так называемые чанки, смысл которых подробно описан здесь: http://www.determina.com/security.research/presentations/recon06/recon06-sotirov.pdf. Пришлось писать свою программу, которая переносит хвосты методов, раскиданные по всему исходнику в сами методы.

2. Если заглянуть в секцию импортов quartz, то там можно увидеть импорт библиотеки msvcrt, динамически прилинковать которую в VS2005 невозможно, по причине ее отсутствия. Поэтому пришлось линковать msvcrt, взятую из VC++ 6.5. Она так же лежит в исходниках в каталоге "Libs".

3. Попытался разделить весь quartz на классы. Для каждого класса отдельный файл. Сложены в каталоге "Classes". Но фактически, это не отдельные исходники, все они включены по include в файл "quartz_code.asm".

4. В исходниках лежит оригинальная quartz.dll, которую я дизассемблировал.

5. Все оригинальные ресурсы восстановлены, лежат в каталоге Res.

Еще несколько важных замечаний:

 1. Т.к. в Ida можно выбрать генерацию ассемблерного текста только для загадочного (как выразился Крис Касперски) ассемблера "generic for Intel 80/86", которого никто никогда не видел и "Borland TASM", который уже лет 10 не обновлялся и с тех же пор не сопровождается, приходится изрядно потрудиться, чтобы этот текст начал ассемблироваться в MASM-е из VS2005. Главная проблема здесь со структурами в качестве локальных переменных, если в теле метода используются поля этой структуры. 
Например, вот фрагмент метода CAVIDynLink::AVIFileOpenW(...)

в Ida он выглядел так:

var_52C      = dword ptr -52Ch
VersionInfo  = OSVERSIONINFOW ptr -528h
WideCharStr  = word ptr -414h
szLongPath   = byte ptr -20Ch
MultiByteStr = byte ptr -108h
var_4        = dword ptr -4

  mov     edi, edi
  push    ebp
  mov     ebp, esp
  sub     esp, 52Ch
  .....
  mov     [ebp+VersionInformation.dwOSVersionInfoSize], 114h
  .....


MASM не понимает конструкцию "OSVERSIONINFOW ptr", поэтому приходится менять ее на:

LOCAL   VersionInfo:OSVERSIONINFO

но тут появляется другая проблема. Все а остальные локальные переменные кроме VersionInfo не что иное как обычный DEFINE и ассемблер всего лишь подставляет в конструкцию
  mov     [ebp+var_52C], eax
"-52Ch" вместо "+var_52C". Но т.к. в исходном тексте переменная VersionInfo оказалась посередине между другими локальными переменными, ассемблер, ничего не зная о существовании остальных локальных переменных назначает для переменной VersionInfo смещение -114h, как будто она первая (нижняя) в списке. Поэтому приходится либо объявлять все остальные переменные с помощью идентификатора LOCAL (но это влечет за собой другие трудности, связанные с "symbol redefinition"), либо перемещать LOCAL переменную вниз, а для всех остальных пересчитывать
смещение. Благо таких методов оказалось не очень много. 
В результате получается следующее:

var_52C      = dword ptr -52Ch     ;             (4)
WideCharStr  = word  ptr -528h     ;           (208h)
szLongPath   = byte  ptr -320h     ;           (104h)
MultiByteStr = byte  ptr -21Ch     ;           (104h)
var_4        = dword ptr -118h     ;             (4)
LOCAL VersionInfo:OSVERSIONINFO    ; ptr -114h (114h)

  sub     esp, 418h
  .....

После этого необходимо исключить из начала метода конструкцию:

  push    ebp
  mov     ebp, esp


т.к. ассемблер при объявлении хотя бы одной LOCAL переменной сделает это при ассемблировании сам и уменьшить число, которое вычитается из ESP для резервирования места для локальных переменных на общую сумму всех переменных, объявленных в этом методе, как LOCAL (по той же
причине).
Затем необходимо изменить [ebp+VersionInfo.dwOSVersionInfoSize] на VersionInfo.dwOSVersionInfoSize

Все вышеописанное уже проделано, но мог где нибудь и ошибиться. Ключевое слово "LOCAL" :-)

2. CLSID
Информацию по этому казусу так и не нашел. Если в ассемблерном тексте объявить строку, в тексте которой будет содержаться "CLSID", ассемблер при ассемблировании заменит "CLSID"
на "GUID", поэтому пришлось перенести все строки, содержащие "CLSID" в файл "Main.h" и объявить их там, как extern "C".

3. Выходной файл в проекте указан "c:\WINDOWS\system32\quartz.dll", а файл, который необходимо стартовать для отладки проекта я указывал GraphEdit и тренировался на нем. Сначала необходимо сохранить свою оригинальную quartz.dll из system32, а затем удалить обе их копии их system32 и из system32/dllcache. 
Так как в WinXP работает служба защиты системных файлов эта процедура требует определенной сноровки, потому что если вы удалите его из каталога system32, эта служба скопирует его из system32/dllcache и наоборот. Используйте для этого bat файл следующего содержания:

del c:\WINDOWS\system32\quartz.dll
del c:\WINDOWS\system32\dllcache\quartz.dll


после его старта появится окно с предупреждением, что системные файлы были изменены и т.п. Так вот, это окно закрывать не нужно, пусть оно висит с немым вопросом до конца вашей работы над проектом, а то после каждой компиляции оно будет появляться вновь.

Скачать проект quartz

PS. Совсем забыл про MASM 9.0, включаемые файлы из которого использованы в проекте. Брать здесь:
http://cracklab.ru/download.php?action=get&n=Njkw

По-моему, в каком то из файлов inc я что-то изменил. Когда будете компилить и компилятор на что-нибудь отругается, сообщите мне (пишите вфорум), если сами не разберетесь.

Comments