.NET 4.x Реализовать хук на D3D9 (DirectX9), чтобы выводить сообщения в чужом окне (игре) - C#
Формулировка задачи:
Здравствуйте уважаемые гуру дотНЕТа.
Помогите плиз.
Хочу реализовать хук на D3D9 (DirectX9), чтобы выводит сообщения в чужом окне (игре) из моего программы.
Для этого нашел пример и взял нужную часть кода, но он то работает то не работает, и даже если заработает, через некоторые время игра кращится, в чем причина?
using System.Threading;
using System.Runtime.InteropServices;
using EasyHook;
using System.Windows.Forms;
using System.Diagnostics;
using SharpDX.Direct3D9;
public class Main : EasyHook.IEntryPoint
{
Device device;
const int D3D9_DEVICE_METHOD_COUNT = 119;
const int D3D9Ex_DEVICE_METHOD_COUNT = 15;
bool _supportsDirect3D9Ex = false;
LocalHook Direct3DDevice_EndSceneHook = null;
LocalHook Direct3DDevice_ResetHook = null;
LocalHook Direct3DDevice_PresentHook = null;
LocalHook Direct3DDeviceEx_PresentExHook = null;
List<IntPtr> id3dDeviceFunctionAddresses = new List<IntPtr>();
protected List<LocalHook> Hooks = new List<LocalHook>();
FileMonInterface Interface;
public Main(RemoteHooking.IContext InContext, String InChannelName)
{
Interface = EasyHook.RemoteHooking.IpcConnectClient<FileMonInterface>(InChannelName);
Interface.Ping();
}
public void Run(RemoteHooking.IContext InContext, String InChannelName)
{
id3dDeviceFunctionAddresses = new List<IntPtr>();
using (Direct3D d3d = new Direct3D())
{
using (var renderForm = new System.Windows.Forms.Form())
{
using (device = new Device(d3d, 0, DeviceType.NullReference, IntPtr.Zero, CreateFlags.HardwareVertexProcessing, new PresentParameters() { BackBufferWidth = 1, BackBufferHeight = 1, DeviceWindowHandle = renderForm.Handle }))
{
id3dDeviceFunctionAddresses.AddRange(GetVTblAddresses(device.NativePointer, D3D9_DEVICE_METHOD_COUNT));
}
}
}
try
{
using (Direct3DEx d3dEx = new Direct3DEx())
{
using (var renderForm = new System.Windows.Forms.Form())
{
using (var deviceEx = new DeviceEx(d3dEx, 0, DeviceType.NullReference, IntPtr.Zero, CreateFlags.HardwareVertexProcessing, new PresentParameters() { BackBufferWidth = 1, BackBufferHeight = 1, DeviceWindowHandle = renderForm.Handle }, new DisplayModeEx() { Width = 800, Height = 600 }))
{
id3dDeviceFunctionAddresses.AddRange(GetVTblAddresses(deviceEx.NativePointer, D3D9_DEVICE_METHOD_COUNT, D3D9Ex_DEVICE_METHOD_COUNT));
_supportsDirect3D9Ex = true;
}
}
}
}
catch (Exception ex)
{
_supportsDirect3D9Ex = false;
MessageBox.Show( ex.ToString());
}
Direct3DDevice_EndSceneHook = LocalHook.Create(
id3dDeviceFunctionAddresses[(int)d3d9_indexes.Direct3DDevice9FunctionOrdinals.EndScene],
new Direct3D9Device_EndSceneDelegate(EndSceneHook),
this);
unsafe
{
if (_supportsDirect3D9Ex)
{
Direct3DDeviceEx_PresentExHook = LocalHook.Create(
id3dDeviceFunctionAddresses[(int)d3d9_indexes.Direct3DDevice9ExFunctionOrdinals.PresentEx],
new Direct3D9DeviceEx_PresentExDelegate(PresentExHook),
this);
}
Direct3DDevice_PresentHook = LocalHook.Create(
id3dDeviceFunctionAddresses[(int)d3d9_indexes.Direct3DDevice9FunctionOrdinals.Present],
new Direct3D9Device_PresentDelegate(PresentHook),
this);
}
Direct3DDevice_ResetHook = LocalHook.Create(
id3dDeviceFunctionAddresses[(int)d3d9_indexes.Direct3DDevice9FunctionOrdinals.Reset],
new Direct3D9Device_ResetDelegate(ResetHook),
this);
Direct3DDevice_EndSceneHook.ThreadACL.SetExclusiveACL(new Int32[1]);
Hooks.Add(Direct3DDevice_EndSceneHook);
Direct3DDevice_PresentHook.ThreadACL.SetExclusiveACL(new Int32[1]);
Hooks.Add(Direct3DDevice_PresentHook);
if (_supportsDirect3D9Ex)
{
Direct3DDeviceEx_PresentExHook.ThreadACL.SetExclusiveACL(new Int32[1]);
Hooks.Add(Direct3DDeviceEx_PresentExHook);
}
Direct3DDevice_ResetHook.ThreadACL.SetExclusiveACL(new Int32[1]);
Hooks.Add(Direct3DDevice_ResetHook);
}
protected IntPtr[] GetVTblAddresses(IntPtr pointer, int numberOfMethods)
{
return GetVTblAddresses(pointer, 0, numberOfMethods);
}
protected IntPtr[] GetVTblAddresses(IntPtr pointer, int startIndex, int numberOfMethods)
{
List<IntPtr> vtblAddresses = new List<IntPtr>();
IntPtr vTable = Marshal.ReadIntPtr(pointer);
for (int i = startIndex; i < startIndex + numberOfMethods; i++)
vtblAddresses.Add(Marshal.ReadIntPtr(vTable, i * IntPtr.Size)); // using IntPtr.Size allows us to support both 32 and 64-bit processes
return vtblAddresses.ToArray();
}
[UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Unicode, SetLastError = true)]
delegate int Direct3D9Device_EndSceneDelegate(IntPtr device);
bool _isUsingPresent = false;
int EndSceneHook(IntPtr devicePtr)
{
Device device = (Device)devicePtr;
if (!_isUsingPresent)
DoCaptureRenderTarget(device, "EndSceneHook");
device.EndScene();
return SharpDX.Result.Ok.Code;
}
.....................
// ТУТ УБРАЛ НЕКОТОРЫЕ КОДЫ КОТОРЫЕ СЧИТАЛ НЕ НУЖНЫМ, ИЗ ЗА ОГРАНИЧЕНИЕ НА ФОРУМЕ
.....................
[UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Unicode, SetLastError = true)]
delegate int Direct3D9Device_ResetDelegate(IntPtr device, ref PresentParameters presentParameters);
object _lockRenderTarget = new object();
Surface _renderTarget;
int ResetHook(IntPtr devicePtr, ref PresentParameters presentParameters)
{
//Device device = (Device)devicePtr;
try
{
lock (_lockRenderTarget)
{
if (_renderTarget != null)
{
_renderTarget.Dispose();
_renderTarget = null;
}
}
device.Reset(presentParameters);
return SharpDX.Result.Ok.Code;
}
catch (SharpDX.SharpDXException sde)
{
return sde.ResultCode.Code;
}
catch (Exception e)
{
MessageBox.Show(e.ToString());
return SharpDX.Result.Ok.Code;
}
}
void DoCaptureRenderTarget(Device device, string hook)
{
try
{
FontDescription f = new FontDescription()
{
Height = 16,
FaceName = "Arial",
Italic = false,
Width = 0,
MipLevels = 1,
CharacterSet = FontCharacterSet.Default,
OutputPrecision = FontPrecision.Default,
Quality = FontQuality.Antialiased,
PitchAndFamily = FontPitchAndFamily.Default | FontPitchAndFamily.DontCare,
Weight = FontWeight.Bold
};
SharpDX.Direct3D9.Font font1 = new Font(device, f);
font1.DrawText(null, "Hooked", 50, 60, new SharpDX.ColorBGRA(255f,100f,100f,1f));
}
catch (Exception e)
{
MessageBox.Show(e.ToString());
}
}Решение задачи: «.NET 4.x Реализовать хук на D3D9 (DirectX9), чтобы выводить сообщения в чужом окне (игре)»
textual
Листинг программы
#include "stdafx.h"
#include <windows.h>
#include <cstdio>
#include <d3d9.h>
#include <d3dx9.h>
#pragma comment(lib, "d3d9.lib")
#pragma comment(lib, "d3dx9.lib")
/*Color's*/
#define GREEN D3DCOLOR_ARGB(255, 000, 255, 000)//Trans(250=SOLID,0=INVISIBLE),Red,Green,Blue
#define BLUE D3DCOLOR_ARGB(255, 000, 000, 255)
LPD3DXFONT m_font = NULL;
boolean DrawMessage(LPD3DXFONT font, unsigned int x, unsigned int y, int alpha, unsigned char r, unsigned char g, unsigned char b, LPCSTR Message)
{ // Create a colour for the text
D3DCOLOR fontColor = D3DCOLOR_ARGB(alpha, r, g, b);
RECT rct; //Font
rct.left=x;
rct.right=150;
rct.top=y;
rct.bottom=rct.top+150;
font->DrawTextA(NULL, Message, -1, &rct, 0, fontColor);
return true;
}
//======ВОТ ТУТ
void stuff(LPDIRECT3DDEVICE9 pDevice, D3DCOLOR Color) //Crosshair function by: Hans211
{
// D3DCOLOR rectColor = D3DCOLOR_XRGB(255,0,255); //No point in using alpha because clear & alpha dont work!
// D3DRECT BarRect = { 10, 10, 40, 40 };
// pDevice->Clear(1,&BarRect, D3DCLEAR_TARGET | D3DCLEAR_TARGET ,rectColor,0,0);
DrawMessage(m_font,40,40,255,255,0,255, "Привет, Мир!");
}
//======ВОТ ТУТ
void *DetourFunc(BYTE *src, const BYTE *dst, const int len) // Old detour from GD Forums.
{
BYTE *jmp = (BYTE*)malloc(len+5);
DWORD dwback;
VirtualProtect(src, len, PAGE_READWRITE, &dwback);
memcpy(jmp, src, len); jmp += len;
jmp[0] = 0xE9;
*(DWORD*)(jmp+1) = (DWORD)(src+len - jmp) - 5;
src[0] = 0xE9;
*(DWORD*)(src+1) = (DWORD)(dst - src) - 5;
VirtualProtect(src, len, dwback, &dwback);
return (jmp-len);
}
typedef HRESULT(__stdcall* EndScene_)(LPDIRECT3DDEVICE9);
EndScene_ pEndScene;//our define
typedef HRESULT (WINAPI* Reset_) (LPDIRECT3DDEVICE9 pDevice, D3DPRESENT_PARAMETERS* pPresentationParameters);
Reset_ pReset;
/*Hooked Endscene*/
HRESULT __stdcall EndScene(LPDIRECT3DDEVICE9 pDevice)
{//Calling our Hook.EndScene makes us able to draw.
D3DXCreateFont( pDevice, 17, 0, FW_BOLD, 0, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, ANTIALIASED_QUALITY, DEFAULT_PITCH | FF_DONTCARE, TEXT("Arial"), &m_font );
stuff(pDevice,BLUE); //Drawing
return pEndScene(pDevice);
}
/*Tools for Hooking by Gordon`*/
bool bCompare(const BYTE* pData, const BYTE* bMask, const char* szMask)//by Gordon`
{
for(;*szMask;++szMask,++pData,++bMask)
if(*szMask=='x' && *pData!=*bMask) return 0;
return (*szMask) == NULL;
}
DWORD FindPattern(DWORD dwAddress,DWORD dwLen,BYTE *bMask,char * szMask)//by Gordon`
{
for(DWORD i=0; i<dwLen; i++)
if (bCompare((BYTE*)(dwAddress+i),bMask,szMask)) return (DWORD)(dwAddress+i);
return 0;
}
DWORD GetAddressPtr(int index) //by Gordon`
{
DWORD* VTableStart = 0;
DWORD dwDevicePointer = FindPattern((DWORD)GetModuleHandle(L"d3d9.dll"), 0x1280000, (PBYTE)"\xC7\x06\x00\x00\x00\x00\x89\x86\x00\x00\x00\x00\x89\x86", "xx????xx????xx");
memcpy(&VTableStart, (void*)(dwDevicePointer+2), 4);
return VTableStart[index];
}
DWORD FindDevice(DWORD Len)//by Gordon`
{
DWORD dwObjBase = 0;
dwObjBase = (DWORD)LoadLibrary(L"D3D9.DLL");
while (dwObjBase++ < dwObjBase + Len)
{
if ( (*(WORD*)(dwObjBase + 0x00)) == 0x06C7
&& (*(WORD*)(dwObjBase + 0x06)) == 0x8689
&& (*(WORD*)(dwObjBase + 0x0C)) == 0x8689
) { dwObjBase += 2; break; }
}
return( dwObjBase );
}
/*The Hook*/
void Hook()
{
PDWORD VTable;
*(DWORD*)&VTable = *(DWORD*)FindDevice(0x128000);
pEndScene = ( EndScene_ )DetourFunc((PBYTE) VTable[42],(PBYTE)EndScene, 5);//Hooking our endscene
Sleep( 100 );
}
/*DLL Main*/
int WINAPI DllMain(HINSTANCE hInst,DWORD reason,LPVOID reserved)
{
switch(reason)
{
case DLL_PROCESS_ATTACH:
CreateThread(0, 0, (LPTHREAD_START_ROUTINE) Hook, 0, 0, 0);//Starting our Hook
break;
}
return true;
}