Страницы

Поиск по вопросам

воскресенье, 15 декабря 2019 г.

Сложность с D3D хуком

#cpp #dll #directx #hook


Здравствуйте! Пытаюсь сделать меню для игрушки, но не могу разобраться в функции,
которая крашит программу после инъекции. Опишу все подробно с комментариями, если я
не прав, пожалуйста поправьте:
Создаю поток в процессе (инжект работает нормально) с таким содержимым:

    DWORD*vtbl = 0;
    //Здесь я записываю начальный адрес модуля 
    DWORD hD3D9 = (DWORD)LoadLibraryA("d3d9.dll");
    //ищу функцию Direct3DCreate или что то другое?
    DWORD table = MemHack->FindPattern(hD3D9, 0x128000, (PBYTE)"\xC7\x06\x00\x00\x00\x00\x89\x86\x00\x00\x00\x00\x89\x86",
"xx????xx????xx");//
    // со смещением в 2 байта копируем указатель
    memcpy(&vtbl, (void*)(table + 2), 4);


Здесь table = 6ace76d3. Вот кусок памяти:

d3d9.Direct3DCreate9Ex+54AC - E8 71000000           - call        d3d9.Direct3DCreate9Ex+5522
d3d9.Direct3DCreate9Ex+54B1 - 33 C0                 - xor eax,eax
d3d9.Direct3DCreate9Ex+54B3 - C7 06 9C86CD6A        - mov [esi],d3d9.dll+869C { [6ACD9D30] }
d3d9.Direct3DCreate9Ex+54B9 - 89 86 08310000        - mov [esi+00003108],eax
d3d9.Direct3DCreate9Ex+54BF - 89 86 00310000        - mov [esi+00003100],eax


Далее идет вызов функции, который крашит программу:

// vtbl[42] указывает на функцию endScene размером 5 байт?
pEndScene = (oEndScene)Mem->Create_Hook((PBYTE)vtbl[42], (PBYTE)myEndScene, 5);


Приведу код функции, который в общем представлении я не понял:

void * cMemory::Create_Hook(BYTE *src, const BYTE *dst, const int len)
{
    BYTE *jmp;
    DWORD dwback;
    DWORD jumpto, newjump;

    VirtualProtect(src,len,PAGE_EXECUTE_READWRITE,&dwback);
    // вот отсюда я не понял зачем эта проверка вообще нужна
    if(src[0] == 0xE9)
    {
        jmp = (BYTE*)malloc(10);
        jumpto = (*(DWORD*)(src+1))+((DWORD)src)+5;
        newjump = (jumpto-(DWORD)(jmp+5));
        jmp[0] = 0xE9;
        *(DWORD*)(jmp+1) = newjump;
        jmp += 5;
        jmp[0] = 0xE9;
        *(DWORD*)(jmp+1) = (DWORD)(src-jmp);
    }
    else
    {
        jmp = (BYTE*)malloc(5+len);
        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;

    for(int i = 5; i < len; i++)
        src[i] = 0x90;

    VirtualProtect(src,len,dwback,&dwback);
    // здесь указатель на функцию?
    return (jmp-len);
}

    


Ответы

Ответ 1



Ваши ошибки: Игра написана на directX8, а не 9 версии, Вы пытаетесь хукнуть 9 версию, собственно LoadLibraryA("d3d9.dll"), нужно LoadLibraryA("d3d8.dll") и в таблице виртуальные методы там, на сколько я помню, имеют немного другую последовательность (для проверки того, какую версию dx использует приложения нужно всего лишь открыть отладчик и просмотреть список загруженных модулей или посмотреть инфо в википедии). Вы пытаетесь(скорее всего, это мои догадки) сделать иньекцию кода в процесс generals.exe, но это просто дочернее окно и оно не выполняет функции отрисовки игрового мира\меню и т.д., Вам нужен процесс game.dat. Вечером, когда приду домой, постараюсь переделать Ваш код в рабочее состояние и дополню ответ. Если Вам интересно, можете почитать интересную статью по Вашей теме. UPD: #include #include #include #pragma comment (lib, "d3d8.lib") #pragma comment (lib, "d3dx8.lib") #pragma comment( lib, "LIBCI.lib" ) #include "MessageControll.h" #include "ConsoleControll.h" //"Game.dat"+0056C9A4 // Hook Function HRESULT WINAPI HookedPresent(LPDIRECT3DDEVICE8 pDevice, CONST RECT* pSourceRect, CONST RECT* pDestRect, HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion); HRESULT WINAPI HookedReset(LPDIRECT3DDEVICE8 pDevice, D3DPRESENT_PARAMETERS *params); // Orig Function typedef HRESULT(WINAPI* tPresent)(LPDIRECT3DDEVICE8 pDevice, CONST RECT* pSourceRect, CONST RECT* pDestRect, HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion); typedef HRESULT(WINAPI *tReset)(LPDIRECT3DDEVICE8 pDevice, D3DPRESENT_PARAMETERS *pp); DWORD origReset = 0, origPresent = 0; tPresent _tPresent = nullptr; tReset _tReset = nullptr; ID3DXFont* pFont = nullptr; void createFont(IDirect3DDevice8* pDevice) { LOGFONT log_font = { 50, //height 0, //width; 0, // lfEscapement; 0, //lfOrientation; FW_BOLD, // lfWeight; FALSE, // lfItalic; FALSE, // lfUnderline; FALSE, // lfStrikeOut; DEFAULT_CHARSET, // lfCharSet; OUT_DEFAULT_PRECIS, //lfOutPrecision; CLIP_DEFAULT_PRECIS, // lfClipPrecision; ANTIALIASED_QUALITY,// lfQuality; DEFAULT_PITCH,// lfPitchAndFamily; "Tahoma"// lfFaceName[LF_FACESIZE]; }; HFONT font = CreateFont(10, 10, 0, 0, FW_NORMAL, false, false, false, DEFAULT_CHARSET, OUT_OUTLINE_PRECIS, 0, ANTIALIASED_QUALITY, DEFAULT_PITCH | FF_DONTCARE, "Arial"); if (D3DXCreateFontIndirect(pDevice, &log_font, &pFont) != D3D_OK) { console("D3DXCreateFontIndirect error!"); } } VOID D3DX_Font(LPDIRECT3DDEVICE8 Device_Interface) { RECT Rect = { 0,0,1000,1000 }; //if (Device_Interface != NULL) //{ // HFONT Logical_Font_Characteristics = CreateFont(16, 0, 0, 0, 400, 0, 0, 0, 0, 0, 0, 2, 0, "Arial"); // if (Logical_Font_Characteristics != NULL) // { // D3DXCreateFont(Device_Interface, Logical_Font_Characteristics, &pFont); // DeleteObject(Logical_Font_Characteristics); // } //} if (pFont != NULL) { pFont->Begin(); pFont->DrawText("StackOverflow.ru!", -1, &Rect, 0, 0xFFFF0000); pFont->End(); } } //========================================================= //if (bDrawText && m_pFont) //{ // PrintTextB(m_pFont, // 250, 20, //x, y // 255, 255, 255, 255, //color values (and then alpha) // "Testing 1234567890!!!"); //} //My custom PrintText Function: //void drawText(const D3DXVECTOR4& area, const DWORD& color, TCHAR *text, ...) //{ // TCHAR buf[1024]{}; // // RECT FontRect = { // // (long)area.x, // (long)area.y, // (long)area.x + (long)area.z, // (long)area.y + (long)area.w // }; // // va_list vaList; // va_start(vaList, text); // //#ifdef UNICODE // vswprintf_s(buf, text, vaList); //#else // vsprintf_s(buf, text, vaList); //#endif // // va_end(vaList); // // pFont->Begin(); // pFont->DrawText(buf, -1, &FontRect, 0, color); // pFont->End(); //} void* DetourCreate(BYTE *src, const BYTE *dst, const int len) { BYTE *jmp; DWORD dwback, dwold; DWORD jumpto, newjump; VirtualProtect(src, len, PAGE_EXECUTE_READWRITE, &dwback); if (src[0] == 0xE9) { jmp = (PBYTE)malloc(10); VirtualProtect(jmp, 10, PAGE_EXECUTE_READWRITE, &dwold); jumpto = (*(DWORD*)(src + 1)) + ((DWORD)src) + 5; newjump = (jumpto - (DWORD)(jmp + 5)); jmp[0] = 0xE9; *(DWORD*)(jmp + 1) = newjump; jmp += 5; jmp[0] = 0xE9; *(DWORD*)(jmp + 1) = (DWORD)(src - jmp); } else { jmp = (PBYTE)malloc(5 + len); VirtualProtect(jmp, 5 + len, PAGE_EXECUTE_READWRITE, &dwold); 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; for (int i = 5; i < len; i++) { src[i] = 0x90; } VirtualProtect(src, len, dwback, &dwback); return (jmp - len); } void GetDevice9Methods() { D3DDISPLAYMODE ds{}; D3DPRESENT_PARAMETERS pp{}; IDirect3DDevice8* dev{}; HMODULE hD3D8Dll = GetModuleHandle("d3d8.dll"); //console("address \"d3d8.dll\" [%#x]", hD3D8Dll); //Инициализируем свой девайс, чтобы узнать адреса функций ресета и презента в виртуальной таблице методов if (hD3D8Dll) { IDirect3D8* d3d8 = Direct3DCreate8(D3D_SDK_VERSION); //console("address \"IDirect3D8\" [%#x]", d3d8); if (d3d8->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &ds) != D3D_OK) { d3d8->Release(); return; } pp.Windowed = 1; pp.SwapEffect = D3DSWAPEFFECT_COPY_VSYNC; pp.BackBufferFormat = ds.Format; if (d3d8->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, GetForegroundWindow(), D3DCREATE_HARDWARE_VERTEXPROCESSING, &pp, &dev) == D3D_OK) { if (dev) { //Копируем адреса виртуальных методов origReset = *((DWORD*)(*(DWORD*)dev) + 14); origPresent = *((DWORD*)(*(DWORD*)dev) + 15); //console("address \"Reset method\" [%#x]", origReset); //console("address \"Present method\" [%#x]", origPresent); dev->Release(); d3d8->Release(); } } else { d3d8->Release(); return; } } } DWORD WINAPI InitThread(HINSTANCE hinstDLL) { //t_con.create(); GetDevice9Methods(); if (origReset && origPresent) { _tPresent = (tPresent)DetourCreate((PBYTE)origPresent, (PBYTE)HookedPresent, 5); _tReset = (tReset)DetourCreate((PBYTE)origReset, (PBYTE)HookedReset, 5); } while (!GetAsyncKeyState(VK_END)) { Sleep(1); } //t_con.del(); FreeLibraryAndExitThread(hinstDLL, 0); return 1; } HRESULT WINAPI HookedPresent(LPDIRECT3DDEVICE8 pDevice, CONST RECT* pSourceRect, CONST RECT* pDestRect, HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) { if (!pFont) { createFont(pDevice); } else { D3DX_Font(pDevice); } D3DRECT rec = { 10, 10, 30, 30 }; //pDevice->Clear(1, &rec, D3DCLEAR_TARGET, 0xFFFF0000, 1.0f, 0); return _tPresent(pDevice, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion); } HRESULT WINAPI HookedReset(LPDIRECT3DDEVICE8 pDevice, D3DPRESENT_PARAMETERS *params) { return _tReset(pDevice, params); } BOOL APIENTRY DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) { switch (fdwReason) { case DLL_PROCESS_ATTACH://Вызывается первым CreateThread(0, 0, LPTHREAD_START_ROUTINE(InitThread), hinstDLL, 0, 0); return 1; case DLL_PROCESS_DETACH://вызывается после освобождения библиотеки break; case DLL_THREAD_ATTACH://вызывается при создании потока break; case DLL_THREAD_DETACH://вызывается после разрушения потока break; } return TRUE; } Как пофиксить проблемы с нехваткой libci: Скачать саму либу и заинклудить в проект; Заинклудить дополнительные зависимости, как сказано тут. Результат:

Комментариев нет:

Отправить комментарий