allasm.ru

    Меню

 

1. Введение

Целью статьи является исследование принципов, позволяющих извлекать трехмерные текстурированные модели из приложений Direct3D.

Задача: Разработать и проверить реализацией методы, которые позволяли бы (без принципиальных изменений) извлекать 3D модели и текстуры из любых приложений, использующих Direct3D.

Требования и ограничения: В силу жесткого ограничения по времени исследования, реализация разработанных методов должна позволять:

  1. Извлекать данные из приложений Direct3D 8, поставляемых с SDK (dx8sdk\samples\Multimedia\Direct3D\bin\), в силу того, что их исходный код легко доступен каждому;
  2. Работать с приложениями не использующие шейдеры (для простоты реализации);
  3. Сохранять: текущий установленный материал, значения вершинного буфера из потока 0, текущие значения буфера индексов и текстуру с индексом 0.

2. Идея:

Идея состоит в подмене функций COM объектов Direct3D, из которых доступны необходимые для извлечения данные.

Все рассматриваемые приложения (1.1), используют для создания COM объекта Direct3D8 функцию Direct3DCreate8 из d3d8.dll. Эта функция возвращает адрес указателя на таблицу указателей на функции объекта Direct3D8 (согласно интерфейсу IDirect3D8). Необходимо ее подменить. При вызове функций CreateDevice из COM объекта Direct3D8 создается COM объект Direct3DDevice8 – основной объект приложения, использующего Direct3D, этот объект имеет функцию DrawIndexedPrimitive, которая используется для «отрисовки» трехмерных моделей в (1.1). Подмены функции IDirect3D8.CreateDevice, на функцию, которая выполнит действительную CreateDevice и подменит в объекте IDirect3DDevice8 DrawIndexedPrimitive, которая выполнит:

  1. cохранение данных в файлы mesh.x и tex.bmp;
  2. вызов действительной функции DrawIndexedPrimitive;
  3. возврат к выполнению программы.
вполне достаточно для реализации цели.
Вся необходимая исходная информация получена из [1], [2], [3], [4], [5].

3. Алгоритмы

  1. Подмена библиотеки d3d8.dll естественно позволяет подменить функцию Direct3DCreate8. Для этого необходимо создать соответствующую библиотеку dll, экспортирующую Direct3DCreate8 и скопировать ее в директорию целевого приложения [6].
  2. Подмена функций СОМ объектов производится записью в таблицу адресов реализованных согласно (2) функций, с сохранением адресов действительных функций.
  3. Параметр obj объектно-ориентированных подмененных функций позволяет получить доступ ко всем функциям COM объекта, и выполнить сохранение необходимых данных.

4. Реализация

Реализация произведена в Flat assembler – version 1.62 by Tomasz Grysztar. При реализации проверка ошибок вызовов сознательно игнорируется, как не входящая в рамки рассматриваемой работы (целью которой не является создание приложения сохраняющего модели из любых программ).
1. Создание dll базируется на примере, поставляемом с fasm. Приведем реализацию функции Direct3DCreate8:

; реализация экспортируемой функции Direct3DCreate8.
d3d8lib  db 'c:\windows\system32\d3d8.dll',0; путь к «дейсвительной» библиотеке
d3d8proc db 'Direct3DCreate8',0; имя «действительной» фунции

proc MyDirect3DCreate8 SDKVersion
	invoke  LoadLibrary,d3d8lib; загрузка d3d8.dll
	invoke  GetProcAddress,eax,d3d8proc; получение адреса Direct3DCreate8
	stdcall eax,[SDKVersion]; выполнение «действительной» Direct3DCreate8

; сохранение адреса IDirect3D8.CreateDevice в переменную CreateDevice
и замещение его на адрес MyCreateDevice
stdcall replace,[eax],IDirect3D8_CreateDevice,MyCreateDevice,
CreateDevice
ret endp

2. Функция замещения адресов в таблице адресов функций COM объекта имеет следующие параметры: IntTblAddr – адрес таблицы, MethodNumber – номер функции, NewFunction — адрес замещающей функции, SaveOldFunction – адрес переменной для сохранения адреса исходной функции.

; реализация функции замещения адресов в COM интерфейсах
proc replace IntTblAddr,MethodNumber,NewFunction,SaveOldFunction
	push	eax
	push	ebx

	; вычисление адреса элемента инерфейса MethodNumber*4+IntTblAddr.
	mov	eax,[MethodNumber]
	shl	eax,2
	add	eax,[IntTblAddr]

	; проверка: не заменена ли уже функция.
	mov	ebx,[eax]
	cmp	[NewFunction],ebx
	je	AlreadyReplaced

	; сохранение адреса исходной функции
	push	eax
	mov	eax,[SaveOldFunction]
	mov	[eax],ebx

	; запись адреса замещающей функции
	mov	eax,[esp]
	invoke	VirtualQuery,eax,mbi,MEMORY_BASIC_INFORMATIONsz

	mov	eax,[esp]
	push	[mbi.Protect]
	invoke	VirtualProtect,eax,4,PAGE_EXECUTE_READWRITE,esp
	add	esp,4

	pop	eax

	mov	ebx,[NewFunction]
	mov	[eax],ebx	; непосредственно запись

	push	PAGE_EXECUTE_READWRITE
	invoke	VirtualProtect,eax,4,[mbi.Protect],esp
	add	esp,4

AlreadyReplaced:

	pop	ebx
	pop	eax
	ret
endp

3. Реализация функций MyCreateDevice и MyDrawIndexedPrimitive является типовой для всех замещаемых функций. В MyCreateDevice вызывается CreateDevice и замещается DrawIndexedPrimitive. В MyDrawIndexedPrimitive, если нажата клавиша F12 происходит сохранение данных, далее вызывается DrawIndexedPrimitive. Параметры функций соответствуют параметрам замещенных [6]:

; реализация замещающих функций
proc MyCreateDevice obj,Adapter, DeviceType, hFocusWindow, BehaviorFlags,
pPresentationParameters, ppReturnedDeviceInterface
; Вызов исходной функции IDirect3D8.CreateDevice invoke CreateDevice,[obj], [Adapter],[DeviceType], [hFocusWindow],
[BehaviorFlags], [pPresentationParameters],[ppReturnedDeviceInterface]
; получение адреса таблицы адресов функций объекта Direct3DDevice8 push eax mov eax,[ppReturnedDeviceInterface] mov eax,[eax] ; замена DrawIndexedPrimitive stdcall replace,[eax],IDirect3DDevice8_DrawIndexedPrimitive,
MyDrawIndexedPrimitive,DrawIndexedPrimitive
pop eax ret endp proc MyDrawIndexedPrimitive obj,Type,MinIndex,NumVertices,
StartIndex,PrimitiveCount
; проверка нажатия F12 invoke GetAsyncKeyState,VK_F12 test eax,eax jns donotsave ; сохранение модели stdcall Save, [obj] donotsave: ; вызов исходной DrawIndexedPrimitive invoke DrawIndexedPrimitive,[obj],[Type],[MinIndex],[NumVertices],
[StartIndex],[PrimitiveCount]
ret endp

4. Реализация функции сохранения текстуры и трехмерного объекта не представляет особого интереса с точки зрения текущего исследования, приведем ее вкратце:

  1. У объекта obj получим установленную текстуру IDirect3DDevice8.GetTexture;

  2. Далее сохраним текстуру с помощью D3DXSaveTextureToFile;

  3. Получим текущий материал IDirect3DDevice8.GetMaterial;

  4. Установим в материале имя файла текущей текстуры;

  5. Получим объект индексов Direct3DIndexBuffer8 через IDirect3DDevice8.GetIndices;

  6. Определим формат индексов и размер буфера индексов IDirect3DIndexBuffer8.GetDesc;

  7. Посчитаем количество треугольников в 3D объекте: (размер буфера индексов)/(размер одного индекса)/3;

  8. Получим объект Direct3DVertexBuffer8, хранящий данные вершин: IDirect3DDevice8.GetStreamSource;

  9. Получим описание размера буфера вершин: IDirect3DVertexBuffer8.GetDesc;

  10. Получим размер одной вершины: D3DXGetFVFVertexSize;

  11. Посчитаем количество всех вершин: (размер буфера)/(размер одной вершины);

  12. Создадим объект D3DXMesh для сохранения данных в файл: D3DXCreateMeshFVF;

  13. Откроем буфер вершин obj для чтения, а D3DXMesh – для записи: IDirect3DVertexBuffer8.Lock, ID3DXMesh.LockVertexBuffer;

  14. Запишем данные в буфер объекта D3DXMesh;

  15. Закроем буферы: IDirect3DIndexBuffer8.Lock, ID3DXMesh.LockIndexBuffer;

  16. Выполним шаги 12 – 14 для индексов;

  17. Сохраним данные в файл формата DirectX: D3DXSaveMeshToX.

5. Результаты

Созданная программа (несмотря на существенные ограничения ее применимости) позволяет доказать реализуемость рассматриваемой технологии.

6. Возможное применение

Наиболее эффективные, на мой взгляд, способы применения описанной технологии в приложениях Direct3D это:

  1. Модификация трехмерных объектов приложений и их текстур;
  2. Извлечение моделей из приложений и использование их в собственных целях (если это не нарушает авторских прав создателей);
  3. При замещении всех функций интерфейсов Direct3D возможна реализация «трехмерных» копий сцен приложений.

7. Достаточные источники:

  1. Эш Рофэйл, Яссер Шохауд. COM и COM+. Полное руководство. Пер. с англ. – К.: ВЕК +, К.: НТИ, М.: Энтроп, 2000.
  2. April 2003 Release of the MSDN Library.
  3. d3d8.h, входящий в состав Microsoft Development Environment 2003.
  4. d3dfile.cpp из DirectX8 SDK.
  5. DirectX 8.1 Programmer's Reference.
  6. Рихтер Дж. Windows для профессионалов: создание эффективных Win32-приложений с учетом специфики 64-разрядной версии Windows/Пер. с англ. – 4-у изд. — СПб: Питер; М.: Издательско-торговый дом «Русская редакция», 2001.