Гайд Хукаем рендер с помощью re_virtualtable

Receiver

🥩 Передай meat, всё в скип, я в темпе
Автор темы
Проверенный
596
805
Всем привет, в данном гайде расскажу как хукнуть рендер warface (directx9 version) с помощью re_virtualtable. Проект у вас уже должен быть готов (dll, x64). Берём классы (спасибо @atizoff) и закидываем в проект. Оффсеты в классах старые, поэтому нужно их обновить. На момент этого гайда (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, качаем его из репозитория и инклюдим. Ну и наконец-то ебашим хук! Создаём экземпляр хука:
C++:
clVirtualTable<HRESULT, LPDIRECT3DDEVICE9, const RECT*, const RECT*, HWND, const RGNDATA*> 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<LPVOID*>(&pDevice);
presentHook.install(pDevice, 17, &presentHooked);
Стоит учесть, что в классах @atizoff возвращаемое значение метода GetDirectDevice - DWORD64, поэтому в классах поменяем его на LPDIRECT3DDEVICE9.
Поскольку там ебанутейший каст, просто оставлю вам это:
C++:
LPDIRECT3DDEVICE9 GetDirectDevice()
{
    return *reinterpret_cast<LPDIRECT3DDEVICE9*>(this + 0xA770);
}
Готово! Хук установлен и осталось только проверить его работоспособность, для этого мы рендерим квадрат с помощью данной функции (спасибо @CleanLegend):
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);
}
И всё прекрасно работает:
1614679851141.png
 
Последнее редактирование:

atizoff

приобретаю кашель за деньги
Проверенный
1,295
1,177
if (!SSystemGlobalEnvironment::Singleton()) std::this_thread::sleep_for(std::chrono::milliseconds(100)); LPDIRECT3DDEVICE9 pDevice = SSystemGlobalEnvironment::Singleton()->GetIRenderer()->GetDirectDevice(); LPVOID pInterface = *reinterpret_cast<LPVOID*>(&pDevice); presentHook.install(pDevice, 17, &presentHooked);
C++:
if (SSystemGlobalEnvironment::Singleton()) {              
    LPDIRECT3DDEVICE9 pDevice = SSystemGlobalEnvironment::Singleton()->GetIRenderer()->GetDirectDevice();
    LPVOID pInterface = *reinterpret_cast<LPVOID*>(&pDevice);
    presentHook.install(pDevice, 17, &presentHooked);
}

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