PDA

Просмотр полной версии : Хукаем рендер с помощью re_virtualtable


Receiver
02.03.2021, 13:10
Всем привет, в данном гайде расскажу как хукнуть рендер warface (directx9 version) с помощью re_virtualtable (https://www.blast.hk/threads/80447/). Проект у вас уже должен быть готов (dll, x64). Берём классы (https://github.com/atizoff/base_warface/blob/master/base_warface/cClasess.h)(спасибо @atizoff (https://www.blast.hk/members/228285/)) и закидываем в проект. Оффсеты в классах старые, поэтому нужно их обновить. На момент этого гайда (02.03.2021) валидные оффсеты:

C++:






SSystemGlobalEnvironment
=
0x141E2E880
GetIRenderer
=
0x48
GetDirectDevice
=
0xA770




Далее нам понадобится заинклюдить классы, и библиотеку thread для создания потока. Теперь приступаем к коду! Первым делом создаём поток в точке входа:

C++:






class
clEntry
{
std
::
thread thread
;
public
:
clEntry
(
)
{
thread
=
std
::
thread
(
[
]
(
)
{
// тут будет наш дальнейший код
}
)
;
}
}
entry
;




В данном случае я использую класс в качестве точки входа. Конструктор класса вызовется при загрзуке модуля в игру, так как мы сразу же создаём объект класса после объявления его самого. Настало время re_virtualtable, качаем его из репозитория (https://github.com/Receiver1/re_virtualtable) и инклюдим. Ну и наконец-то ебашим хук! Создаём экземпляр хука:

C++:






clVirtualTable

presentHook
;




Перед как ставить хук создадим функцию которая будет его обрабатывать:

C++:






HRESULT __stdcall
presentHooked
(
IDirect3DDevice9
*
pDevice
,
const
RECT
*
pSourceRect
,
const
RECT
*
pDestRect
,
HWND hDestWindowOverride
,
const
RGNDATA
*
pDirtyRegion
)
{
}




Но это не будет работать правильно, если мы не вызовем оригинальную функцию, поэтому добавляем вызов оригинала в нашу функцию обработчик:

C++:






return
presentHook
.
call
(
eConvention
::
stdcall
,
pDevice
,
pSourceRect
,
pDestRect
,
hDestWindowOverride
,
pDirtyRegion
)
;




В нашем созданном потоке ждём инициализации SSystemGlobalEnvironment и ставим хук:

C++:






if
(
!
SSystemGlobalEnvironment
::
Singleton
(
)
)
std
::
this_thread
::
sleep_for
(
std
::
chrono
::
milliseconds
(
100
)
)
;
LPDIRECT3DDEVICE9 pDevice
=
SSystemGlobalEnvironment
::
Singleton
(
)
->
GetIRenderer
(
)
->
GetDirectDevice
(
)
;
LPVOID pInterface
=
*
reinterpret_cast

(
&
pDevice
)
;
presentHook
.
install
(
pDevice
,
17
,
&
presentHooked
)
;




Стоит учесть, что в классах @atizoff (https://www.blast.hk/members/228285/) возвращаемое значение метода GetDirectDevice - DWORD64, поэтому в классах поменяем его на LPDIRECT3DDEVICE9.

Поскольку там ебанутейший каст, просто оставлю вам это:

C++:






LPDIRECT3DDEVICE9
GetDirectDevice
(
)
{
return
*
reinterpret_cast

(
this
+
0xA770
)
;
}




Готово! Хук установлен и осталось только проверить его работоспособность, для этого мы рендерим квадрат с помощью данной функции (спасибо @CleanLegend (https://www.blast.hk/members/268/)):

C++:






void
DrawRect
(
LPDIRECT3DDEVICE9 m_pDevice
,
int
X
,
int
Y
,
int
L
,
int
H
,
D3DCOLOR color
)
{
D3DRECT rect
=
{
X
,
Y
,
X
+
L
,
Y
+
H
}
;
m_pDevice
->
Clear
(
1
,
&
rect
,
D3DCLEAR_TARGET
,
color
,
0
,
0
)
;
}




И всё прекрасно работает:

https://forum.antichat.xyz/attachments/27682289/

atizoff
02.03.2021, 15:49
if (!SSystemGlobalEnvironment::Singleton()) std::this_thread::sleep_for(std::chrono::milliseco nds(100)); LPDIRECT3DDEVICE9 pDevice = SSystemGlobalEnvironment::Singleton()->GetIRenderer()->GetDirectDevice(); LPVOID pInterface = *reinterpret_cast(&pDevice); presentHook.install(pDevice, 17, &presentHooked);



C++:






if
(
SSystemGlobalEnvironment
::
Singleton
(
)
)
{
LPDIRECT3DDEVICE9 pDevice
=
SSystemGlobalEnvironment
::
Singleton
(
)
->
GetIRenderer
(
)
->
GetDirectDevice
(
)
;
LPVOID pInterface
=
*
reinterpret_cast

(
&
pDevice
)
;
presentHook
.
install
(
pDevice
,
17
,
&
presentHooked
)
;
}




и не надо потоки вызывать. а так конкретно этот класс на пустоту проверять бесполезно, он всегда наполнен. в такой проверке науждаются лишь IGameFramework, ICVar (SCVars) (из распрастраннёных), тем не менее отличный гайд!