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/
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/