HRESULT WINAPI D3D10CreateDeviceAndSwapChainHook(IDXGIAdapter *pAdapter, D3D10_DRIVER_TYPE DriverType, HMODULE Software, UINT Flags, UINT SDKVersion, DXGI_SWAP_CHAIN_DESC *pSwapChainDesc, IDXGISwapChain **ppSwapChain, ID3D10Device **ppDevice) { printf("In D3D10CreateDeviceAndSwapChainHook\n"); //Create the device and swap chain HRESULT hResult = pD3D10CreateDeviceAndSwapChain(pAdapter, DriverType, Software, Flags, SDKVersion, pSwapChainDesc, ppSwapChain, ppDevice); //Save the device and swap chain interface. //These aren't used in this example but are generally nice to have addresses to if(ppSwapChain == NULL) { printf("Swap chain is NULL.\n"); return hResult; } else { pSwapChain = *ppSwapChain; } if(ppDevice == NULL) { printf("Device is NULL.\n"); return hResult; } else { pDevice = *ppDevice; } //Get the vtable address of the swap chain's Present function and modify it with our own. //Save it to return to later in our Present hook if(pSwapChain != NULL) { DWORD_PTR *SwapChainVTable = (DWORD_PTR *)pSwapChain; SwapChainVTable = (DWORD_PTR *)SwapChainVTable[0]; printf("Swap chain VTable: %X\n", SwapChainVTable); PresentAddress = (pPresent)SwapChainVTable[8]; printf("Present address: %X\n", PresentAddress); DWORD OldProtections = 0; VirtualProtect(&SwapChainVTable[8], sizeof(DWORD_PTR), PAGE_EXECUTE_READWRITE, &OldProtections); SwapChainVTable[8] = (DWORD_PTR)PresentHook; VirtualProtect(&SwapChainVTable[8], sizeof(DWORD_PTR), OldProtections, &OldProtections); } //Create the font that we will be drawing with CreateDrawingFont(); return hResult; }
/// Prepares DXGI and D3D10 data by trying to determining the module filepath /// and function offsets in memory. /// (This data can later be used for hooking / code injection. /// /// Adjusts the data behind the global variables dxgi and d3d10. void PrepareDXGI10(IDXGIAdapter1 *pAdapter, bool initializeDXGIData) { if (!dxgi || !d3d10 || !pAdapter) return; ods("D3D10: Preparing static data for DXGI and D3D10 Injection"); d3d10->wcFileName[0] = 0; d3d10->iOffsetAddRef = 0; d3d10->iOffsetRelease = 0; HMODULE hD3D10 = LoadLibrary("D3D10.DLL"); if (hD3D10 != NULL) { HWND hwnd = CreateWindowW(L"STATIC", L"Mumble DXGI Window", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 640, 480, 0, NULL, NULL, 0); D3D10CreateDeviceAndSwapChainType pD3D10CreateDeviceAndSwapChain = reinterpret_cast<D3D10CreateDeviceAndSwapChainType>(GetProcAddress(hD3D10, "D3D10CreateDeviceAndSwapChain")); DXGI_SWAP_CHAIN_DESC desc; ZeroMemory(&desc, sizeof(desc)); RECT rcWnd; GetClientRect(hwnd, &rcWnd); desc.BufferDesc.Width = rcWnd.right - rcWnd.left; desc.BufferDesc.Height = rcWnd.bottom - rcWnd.top; ods("D3D10: Got ClientRect W %d H %d", desc.BufferDesc.Width, desc.BufferDesc.Height); desc.BufferDesc.RefreshRate.Numerator = 60; desc.BufferDesc.RefreshRate.Denominator = 1; desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB; desc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED; desc.BufferDesc.Scaling = DXGI_MODE_SCALING_CENTERED; desc.SampleDesc.Count = 1; desc.SampleDesc.Quality = 0; desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; desc.BufferCount = 2; desc.OutputWindow = hwnd; desc.Windowed = true; desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; IDXGISwapChain *pSwapChain = NULL; ID3D10Device *pDevice = NULL; HRESULT hr = pD3D10CreateDeviceAndSwapChain(pAdapter, D3D10_DRIVER_TYPE_HARDWARE, NULL, 0, D3D10_SDK_VERSION, &desc, &pSwapChain, &pDevice); if (FAILED(hr)) ods("D3D10: pD3D10CreateDeviceAndSwapChain failure!"); if (pDevice && pSwapChain) { // For VC++ the vtable is located at the base addr. of the object and each function entry is a single pointer. Since p.e. the base classes // of IDXGISwapChain have a total of 8 functions the 8+Xth entry points to the Xth added function in the derived interface. void ***vtbl = (void ***) pSwapChain; void *pPresent = (*vtbl)[8]; int offset = GetFnOffsetInModule(reinterpret_cast<voidFunc>(pPresent), dxgi->wcFileName, ARRAY_NUM_ELEMENTS(dxgi->wcFileName), "D3D10", "Present"); if (offset >= 0) { if (initializeDXGIData) { dxgi->iOffsetPresent = offset; ods("D3D10: Successfully found Present offset: %ls: %d", dxgi->wcFileName, dxgi->iOffsetPresent); } else { if (dxgi->iOffsetPresent == offset) { ods("D3D10: Successfully verified Present offset: %ls: %d", dxgi->wcFileName, dxgi->iOffsetPresent); } else { ods("D3D10: Failed to verify Present offset for %ls. Found %d, but previously found %d.", dxgi->wcFileName, offset, dxgi->iOffsetPresent); } } } void *pResize = (*vtbl)[13]; offset = GetFnOffsetInModule(reinterpret_cast<voidFunc>(pResize), dxgi->wcFileName, ARRAY_NUM_ELEMENTS(dxgi->wcFileName), "D3D10", "ResizeBuffers"); if (offset >= 0) { if (initializeDXGIData) { dxgi->iOffsetResize = offset; ods("D3D10: Successfully found ResizeBuffers offset: %ls: %d", dxgi->wcFileName, dxgi->iOffsetResize); } else { if (dxgi->iOffsetResize == offset) { ods("D3D10: Successfully verified ResizeBuffers offset: %ls: %d", dxgi->wcFileName, dxgi->iOffsetResize); } else { ods("D3D10: Failed to verify ResizeBuffers offset for %ls. Found %d, but previously found %d.", dxgi->wcFileName, offset, dxgi->iOffsetResize); } } } vtbl = (void ***) pDevice; void *pAddRef = (*vtbl)[1]; offset = GetFnOffsetInModule(reinterpret_cast<voidFunc>(pAddRef), d3d10->wcFileName, ARRAY_NUM_ELEMENTS(d3d10->wcFileName), "D3D10", "AddRef"); if (offset >= 0) { d3d10->iOffsetAddRef = offset; ods("D3D10: Successfully found AddRef offset: %ls: %d", d3d10->wcFileName, d3d10->iOffsetAddRef); } void *pRelease = (*vtbl)[2]; offset = GetFnOffsetInModule(reinterpret_cast<voidFunc>(pRelease), d3d10->wcFileName, ARRAY_NUM_ELEMENTS(d3d10->wcFileName), "D3D10", "Release"); if (offset >= 0) { d3d10->iOffsetRelease = offset; ods("D3D10: Successfully found Release offset: %ls: %d", d3d10->wcFileName, d3d10->iOffsetRelease); } } if (pDevice) pDevice->Release(); if (pSwapChain) pSwapChain->Release(); DestroyWindow(hwnd); } else { FreeLibrary(hD3D10); } }
extern "C" __declspec(dllexport) void __cdecl PrepareDXGI() { // This function is called by the Mumble client in Mumble's scope // mainly to extract the offsets of various functions in the IDXGISwapChain // and IDXGIObject interfaces that need to be hooked in target // applications. The data is stored in the dxgi shared memory structure. if (! dxgi) return; ods("Preparing static data for DXGI Injection"); dxgi->wcDXGIFileName[0] = 0; dxgi->wcD3D10FileName[0] = 0; dxgi->iOffsetPresent = 0; dxgi->iOffsetResize = 0; dxgi->iOffsetAddRef = 0; dxgi->iOffsetRelease = 0; OSVERSIONINFOEXW ovi; memset(&ovi, 0, sizeof(ovi)); ovi.dwOSVersionInfoSize = sizeof(ovi); GetVersionExW(reinterpret_cast<OSVERSIONINFOW *>(&ovi)); if ((ovi.dwMajorVersion >= 7) || ((ovi.dwMajorVersion == 6) && (ovi.dwBuildNumber >= 6001))) { // Make sure this is vista or greater as quite a number of <=WinXP users have fake DX10 libs installed HMODULE hD3D10 = LoadLibrary("D3D10.DLL"); HMODULE hDXGI = LoadLibrary("DXGI.DLL"); if (hDXGI != NULL && hD3D10 != NULL) { CreateDXGIFactoryType pCreateDXGIFactory = reinterpret_cast<CreateDXGIFactoryType>(GetProcAddress(hDXGI, "CreateDXGIFactory")); ods("Got %p", pCreateDXGIFactory); if (pCreateDXGIFactory) { HRESULT hr; IDXGIFactory * pFactory; hr = pCreateDXGIFactory(__uuidof(IDXGIFactory), (void**)(&pFactory)); if (pFactory) { HWND hwnd = CreateWindowW(L"STATIC", L"Mumble DXGI Window", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 640, 480, 0, NULL, NULL, 0); IDXGIAdapter *pAdapter = NULL; pFactory->EnumAdapters(0, &pAdapter); D3D10CreateDeviceAndSwapChainType pD3D10CreateDeviceAndSwapChain = reinterpret_cast<D3D10CreateDeviceAndSwapChainType>(GetProcAddress(hD3D10, "D3D10CreateDeviceAndSwapChain")); IDXGISwapChain *pSwapChain = NULL; ID3D10Device *pDevice = NULL; DXGI_SWAP_CHAIN_DESC desc; ZeroMemory(&desc, sizeof(desc)); RECT rcWnd; GetClientRect(hwnd, &rcWnd); desc.BufferDesc.Width = rcWnd.right - rcWnd.left; desc.BufferDesc.Height = rcWnd.bottom - rcWnd.top; ods("W %d H %d", desc.BufferDesc.Width, desc.BufferDesc.Height); desc.BufferDesc.RefreshRate.Numerator = 60; desc.BufferDesc.RefreshRate.Denominator = 1; desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB; desc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED; desc.BufferDesc.Scaling = DXGI_MODE_SCALING_CENTERED; desc.SampleDesc.Count = 1; desc.SampleDesc.Quality = 0; desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; desc.BufferCount = 2; desc.OutputWindow = hwnd; desc.Windowed = true; desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; hr = pD3D10CreateDeviceAndSwapChain(pAdapter, D3D10_DRIVER_TYPE_HARDWARE, NULL, 0, D3D10_SDK_VERSION, &desc, &pSwapChain, &pDevice); if (pDevice && pSwapChain) { HMODULE hRef; // For VC++ the vtable is located at the base addr. of the object and each function entry is a single pointer. Since p.e. the base classes // of IDXGISwapChain have a total of 8 functions the 8+Xth entry points to the Xth added function in the derived interface. void ***vtbl = (void ***) pSwapChain; void *pPresent = (*vtbl)[8]; if (! GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, (char *) pPresent, &hRef)) { ods("DXGI: Failed to get module for Present"); } else { GetModuleFileNameW(hRef, dxgi->wcDXGIFileName, 2048); unsigned char *b = (unsigned char *) pPresent; unsigned char *a = (unsigned char *) hRef; dxgi->iOffsetPresent = b-a; ods("DXGI: Successfully found Present offset: %ls: %d", dxgi->wcDXGIFileName, dxgi->iOffsetPresent); } void *pResize = (*vtbl)[13]; if (! GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, (char *) pResize, &hRef)) { ods("DXGI: Failed to get module for ResizeBuffers"); } else { wchar_t buff[2048]; GetModuleFileNameW(hRef, buff, 2048); if (wcscmp(buff, dxgi->wcDXGIFileName) == 0) { unsigned char *b = (unsigned char *) pResize; unsigned char *a = (unsigned char *) hRef; dxgi->iOffsetResize = b-a; ods("DXGI: Successfully found ResizeBuffers offset: %ls: %d", dxgi->wcDXGIFileName, dxgi->iOffsetResize); } } vtbl = (void ***) pDevice; void *pAddRef = (*vtbl)[1]; if (! GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, (char *) pAddRef, &hRef)) { ods("D3D10: Failed to get module for AddRef"); } else { GetModuleFileNameW(hRef, dxgi->wcD3D10FileName, 2048); unsigned char *b = (unsigned char *) pAddRef; unsigned char *a = (unsigned char *) hRef; dxgi->iOffsetAddRef = b-a; ods("D3D10: Successfully found AddRef offset: %ls: %d", dxgi->wcD3D10FileName, dxgi->iOffsetAddRef); } void *pRelease = (*vtbl)[2]; if (! GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, (char *) pRelease, &hRef)) { ods("D3D10: Failed to get module for Release"); } else { wchar_t buff[2048]; GetModuleFileNameW(hRef, buff, 2048); if (wcscmp(buff, dxgi->wcD3D10FileName) == 0) { unsigned char *b = (unsigned char *) pRelease; unsigned char *a = (unsigned char *) hRef; dxgi->iOffsetRelease = b-a; ods("D3D10: Successfully found Release offset: %ls: %d", dxgi->wcD3D10FileName, dxgi->iOffsetRelease); } } } if (pDevice) pDevice->Release(); if (pSwapChain) pSwapChain->Release(); DestroyWindow(hwnd); pFactory->Release(); } } } } else { ods("No DXGI pre-Vista"); } }