За заготовку возьмем готовый пример Wallhack от RaXoR
Код:
library lib;
{$R *.dres}
uses
Windows,
classes,
SysUtils,
advApiHook,
Direct3D9,
D3DX9;
{$R *.res}
var
g_Font : ID3DXFont;
TextRect: TRect;
StridesN: integer;
Wallhack:boolean=false;
wall : string;
var EndScene9Next : function (self: pointer): HResult stdcall = nil;
var CreateDevice9Next: function (self: pointer; Adapter: LongWord; DeviceType: TD3DDevType; hFocusWindow: HWND; BehaviorFlags: DWord; pPresentationParameters: PD3DPresentParameters; out ppReturnedDeviceInterface: IDirect3DDevice9): HResult; stdcall = nil;
var Direct3DCreate9Next: function (SDKVersion: LongWord): DWORD stdcall = nil;
var ResetNext: function (self: pointer; const pPresentationParameters: TD3DPresentParameters): HResult; stdcall;
var SetStreamSourceNext: function (self: pointer; StreamNumber: LongWord; pStreamData: IDirect3DVertexBuffer9; OffsetInBytes, Stride: LongWord): HResult; stdcall;
var DrawIndexedPrimitiveNext: function (DeviceInterface: IDirect3DDevice9; _Type: TD3DPrimitiveType; BaseVertexIndex: Integer; MinVertexIndex, NumVertices, startIndex, primCount: LongWord): HResult; stdcall;
procedure CheckPressed;
begin
if (GetAsyncKeyState(VK_NUMPAD1) and 1)<> 0 then
begin
wallhack:= not wallhack;
end;
end;
procedure All_OnLostDevice;
begin
g_Font.OnLostDevice;
end;
procedure All_OnResetDevice;
begin
g_Font.OnResetDevice;
end;
function ResetCallback(self: pointer; const pPresentationParameters: TD3DPresentParameters): HResult; stdcall;
begin
All_OnLostDevice;
result:= ResetNext(self,pPresentationParameters);
if( SUCCEEDED(result) ) then
begin
All_OnResetDevice;
end;
end;
function SetStreamSourceCallback(self: pointer; StreamNumber: LongWord; pStreamData: IDirect3DVertexBuffer9; OffsetInBytes, Stride: LongWord): HResult; stdcall;
begin
StridesN := Stride;
result := SetStreamSourceNext(self,StreamNumber,pStreamData,OffsetInBytes, StridesN);
end;
function EndScene9Callback(self: pointer): HResult; stdcall;
begin
CheckPressed;
if Wallhack then wall := 'On' else wall := 'Off';
g_Font.DrawTextW(nil,PWideChar('Walhack: '+ wall),-1,@TextRect,DT_LEFT or DT_NOCLIP,D3DCOLOR_ARGB(255,0,255,0));
Result:=EndScene9Next(self);
end;
function DrawIndexedPrimitiveCallback(DeviceInterface: IDirect3DDevice9; _Type: TD3DPrimitiveType; BaseVertexIndex: Integer; MinVertexIndex, NumVertices, startIndex, primCount: LongWord): HResult; stdcall;
begin
if (Wallhack = true) then
begin
if (StridesN = 20) and (NumVertices>0) then
begin
DeviceInterface.SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE);
DrawIndexedPrimitiveNext(DeviceInterface, _Type, BaseVertexIndex, MinVertexIndex, NumVertices, startIndex, primCount);
DeviceInterface.SetRenderState(D3DRS_ZENABLE, D3DZB_TRUE);
end;
end;
result := DrawIndexedPrimitiveNext(DeviceInterface, _Type, BaseVertexIndex, MinVertexIndex, NumVertices, startIndex, primCount);
end;
function CreateDevice9Callback(self: pointer; Adapter: LongWord; DeviceType: TD3DDevType; hFocusWindow: HWND; BehaviorFlags: DWord; pPresentationParameters: PD3DPresentParameters; out ppReturnedDeviceInterface: IDirect3DDevice9): HResult; stdcall;
begin
Result :=CreateDevice9Next(self,Adapter,DeviceType, hFocusWindow,BehaviorFlags,pPresentationParameters,ppReturnedDeviceInterface);
if (result = 0) then
begin
TextRect:=Rect(15,25,0,0);
D3DXCreateFont(ppReturnedDeviceInterface,20,0,FW_Bold,1,false,DEFAULT_CHARSET,OUT_DEFAULT_PRECIS,
6,DEFAULT_PITCH or FF_DONTCARE,PChar('Sylfaen'),g_Font);
HookCode(GetInterfaceMethod(ppReturnedDeviceInterface, 42), @EndScene9Callback, @EndScene9Next);
HookCode(GetInterfaceMethod(ppReturnedDeviceInterface, 16), @ResetCallback, @ResetNext);
HookCode(GetInterfaceMethod(ppReturnedDeviceInterface, 100),@SetStreamSourceCallback, @SetStreamSourceNext);
HookCode(GetInterfaceMethod(ppReturnedDeviceInterface, 82), @DrawIndexedPrimitiveCallback, @DrawIndexedPrimitiveNext);
end
end;
function Direct3DCreate9Callback(SDKVersion: LongWord): DWORD; stdcall;
begin
Result:=Direct3DCreate9Next(SDKVersion);
if (Result <> 0) then
begin
if (@CreateDevice9Next <> nil) then
UnhookCode(@CreateDevice9Next);
HookCode(GetInterfaceMethod(result, 16), @CreateDevice9Callback, @CreateDevice9Next);
end;
end;
procedure DLLEntryPoint(dwReason:DWord);
begin
case dwReason of
DLL_PROCESS_ATTACH:
begin
HookProc('d3d9.dll', 'Direct3DCreate9', @Direct3DCreate9Callback, @Direct3DCreate9Next);
end;
DLL_PROCESS_DETACH:
begin
end;
end;
end;
begin
DllProc:= @DLLEntryPoint;
DLLEntryPoint(DLL_PROCESS_ATTACH);
end.
Для загрузки мы будем использовать функцию D3DXCreateTextureFromFile()
Учтите:
D3DXCreateTextureFromFile() для загрузки изображений из файлов, в качестве файлов можно задавать почти любой популярный формат (bmp, jpeg, tga, tiff и т.д.). Важно только помнить - что лучше всего использовать квадратные текстуры со стороной кратной степени двойки (2, 4, 8, 16, 32, 64, 128, 256, 512, 1024 и т.д.).
Выглядеть это будет примерно так:
Код:
D3DXCreateTextureFromFile(Device,PWideChar(FileName), TextureName);
Поскольку в качестве Device в функции DrawIndexedPrimitiveCallback в качестве девайса у нас выступает DeviceInterface
Код:
DeviceInterface: IDirect3DDevice9;
То собственно и объявим его также в глобальных переменных проекта
Код:
Var
DeviceInterface: IDirect3DDevice9;
В качестве FileName нужно указать имя файла и его путь:
Код:
PWideChar('yellow.bmp') Это означает, что мы загрузим файл yellow.bmp из папки, где располагается исполнительный .exe файл игры, в который будет происходить инжект при создании процесса игры, а значит и сам файл yellow.bmp должен находится в этой папке.
По изученным выше сведениям, создаем yellow.bmp размером 4х4 (степень двойки)
и заливаем его желтым цветом. Сохраняем картинку с глубиной 24bit.
2 составные этой цепочки собраны, осталось лишь назначить текстуру, в которую будет происходить загрузка картинки.
По аналогии, назовем ее yellow
Описываем её в глобальных переменных
Код:
Var
yellow:IDirect3DTexture9;
И в результате получаем функцию такого типа:
Код:
D3DXCreateTextureFromFile(DeviceInterface,PWideChar('yellow.bmp'), yellow); И прописываем её в DrawIndexedPrimitiveCallback
Код:
function DrawIndexedPrimitiveCallback(DeviceInterface: IDirect3DDevice9; _Type: TD3DPrimitiveType; BaseVertexIndex: Integer; MinVertexIndex, NumVertices, startIndex, primCount: LongWord): HResult; stdcall;
begin
D3DXCreateTextureFromFile(DeviceInterface,PWideChar('yellow.bmp'), yellow);
if (wallhack = true) then
begin
if (StridesN = 20) and (NumVertices>0) then
begin
DeviceInterface.SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE);
DrawIndexedPrimitiveNext(DeviceInterface, _Type, BaseVertexIndex, MinVertexIndex, NumVertices, startIndex, primCount);
DeviceInterface.SetRenderState(D3DRS_ZENABLE, D3DZB_TRUE);
end;
end;
result := DrawIndexedPrimitiveNext(DeviceInterface, _Type, BaseVertexIndex, MinVertexIndex, NumVertices, startIndex, primCount);
end; Осталось присвоить текстуре с заданными StridesN и NumVertices присвоить нашу текстуру
Используем функцию SetTexture:
Код:
Deviceinterface.SetTexture(0,TextureName);
где TextureName - имя текстуры, в нашем случаем - yellow
И таким образом получаем:
Код:
function DrawIndexedPrimitiveCallback(DeviceInterface: IDirect3DDevice9; _Type: TD3DPrimitiveType; BaseVertexIndex: Integer; MinVertexIndex, NumVertices, startIndex, primCount: LongWord): HResult; stdcall;
begin
D3DXCreateTextureFromFile(DeviceInterface,PWideChar('yellow.bmp'), yellow);
if (wallhack = true) then
begin
if (StridesN = 20) and (NumVertices>0) then
begin
DeviceInterface.SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE);
Deviceinterface.SetTexture(0,yellow);
DrawIndexedPrimitiveNext(DeviceInterface, _Type, BaseVertexIndex, MinVertexIndex, NumVertices, startIndex, primCount);
Deviceinterface.SetTexture(0,yellow);
DeviceInterface.SetRenderState(D3DRS_ZENABLE, D3DZB_TRUE);
end;
end;
result := DrawIndexedPrimitiveNext(DeviceInterface, _Type, BaseVertexIndex, MinVertexIndex, NumVertices, startIndex, primCount);
end; Компилим, инжектим, получаем результат.
Но есть один недостаток - поскольку текстура загружается с частотой обновления экрана без перерыва, то и на выходе получаем перезаполнение памяти или серьезную просадку FPS в игре (до 1 в зависимости от времени)
Поэтому немного схитрим:
1) В глобальных переменных
Изменяем функцию:
Код:
function DrawIndexedPrimitiveCallback(DeviceInterface: IDirect3DDevice9; _Type: TD3DPrimitiveType; BaseVertexIndex: Integer; MinVertexIndex, NumVertices, startIndex, primCount: LongWord): HResult; stdcall;
begin
if r<=5 then
begin
r:=r+1; //ограничение кол-ва загрузок с запасом(на вся)
D3DXCreateTextureFromFile(DeviceInterface,PWideChar('yellow.bmp'), yellow);
end;
if (wallhack = true) then
begin
if (StridesN = 20) and (NumVertices>0) then
begin
DeviceInterface.SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE);
Deviceinterface.SetTexture(0,yellow);
DrawIndexedPrimitiveNext(DeviceInterface, _Type, BaseVertexIndex, MinVertexIndex, NumVertices, startIndex, primCount);
Deviceinterface.SetTexture(0,yellow);
DeviceInterface.SetRenderState(D3DRS_ZENABLE, D3DZB_TRUE);
end;
end;
result := DrawIndexedPrimitiveNext(DeviceInterface, _Type, BaseVertexIndex, MinVertexIndex, NumVertices, startIndex, primCount);
end; Присваиваем счетчику начальное значение:
Код:
begin
r:=1;
DllProc:= @DLLEntryPoint;
DLLEntryPoint(DLL_PROCESS_ATTACH);
end.
Вот и всё!