As the title says, i'm trying to hook DirectX 9 V-Table and show some information on screen, I've been studying detours and hooking for a couple days now and i thought i understood it to a fair extent, but now i'm not too sure how to debug this issue.
My hook is calling another function ShowMsg(), which will eventually be a draw function, but for now it just shows a message-box.
My ShowMsg() function is called, but then the program is crashing.
I'm using the DirectX Feb 2010 "SimpleSample" application.
Here's my code, the commented parts are from a previous test at hooking a function from another test application.
// dllmain.cpp : Defines the entry point for the DLL application.
#include "stdafx.h"
#include <iostream>
#include <Windows.h>
#include "VirtualTable.h"
#include <d3d9.h>
#pragma comment(lib, "d3d9.lib")
#include <d3dx9.h>
#pragma comment(lib, "d3dx9.lib")
#include <detours.h>
#pragma comment(lib, "detours.lib")
using namespace std;
typedef void(__thiscall* Present)(IDirect3DDevice9* device);
Present g_org_Present;
void ShowMsg()
{
MessageBoxA(0, "This function was called.", "", 0);
}
void __fastcall hk_Present(IDirect3DDevice9* device)
{
ShowMsg();
//call the original function
g_org_Present(device);
}
void InitiateHooks()
{
HWND game_window = FindWindowA(NULL, "SimpleSample");
auto d3dpp = D3DPRESENT_PARAMETERS{};
auto d3d = Direct3DCreate9(D3D_SDK_VERSION);
IDirect3DDevice9* device;
d3dpp.BackBufferCount = 1;
d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.hDeviceWindow = game_window;
d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
d3dpp.BackBufferFormat = D3DFMT_R5G6B5;
d3dpp.Windowed = TRUE;
if (SUCCEEDED(d3d->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, game_window, D3DCREATE_HARDWARE_VERTEXPROCESSING, &d3dpp, &device)))
{
void** vmt = *(void***)device;
DWORD oldProtection;
VirtualProtect(&vmt[17], 4, PAGE_EXECUTE_READWRITE, &oldProtection);
g_org_Present = (Present)vmt[17];
vmt[17] = &hk_Present;
VirtualProtect(&vmt[17], 4, oldProtection, 0);
device->Present(NULL, NULL, NULL, NULL);
}
// VirtualTable* myTable = new VirtualTable();
//get the pointer to the actual virtual method table from our pointer to our class instance
// void** base = *(void***)myTable;
// DWORD oldProtection;
//one way to remove page protection(not the best but this is an example only)
// VirtualProtect(&base[1], 4, PAGE_EXECUTE_READWRITE, &oldProtection);
//save the original function
// g_org_VirtualFunction01 = (VirtualFunction01_t)base[1];
//overwrite
// base[1] = &hk_VirtualFunction01;
//restore page protection
// VirtualProtect(&base[1], 4, oldProtection, 0);
//call the virtual function (now hooked) from our class instance
// myTable->VirtualFunction01();
}
#pragma endregion
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
CreateThread(0, 0x1000, (LPTHREAD_START_ROUTINE)InitiateHooks, 0, 0, NULL);
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
Can someone please give me an idea of what i might be doing wrong here, so i can fix this, and for future reference.
Here's updated code, i realised i shouldn't be calling the function directly so i changed that, also changed it to try hook/detour EndScene, also using MS Detours instead of the other method which i think is V-Table patching, it seems like my EndScene hook is being called, as the MessageBox is continuously called. However, the program still crashes if i comment out the MessageBox.
#include "stdafx.h"
#include <iostream>
#include <Windows.h>
#include <intrin.h>
#include <tchar.h>
#include <tlhelp32.h>
#include <Psapi.h>
#include <winsock2.h>
#include <vector>
#include <ws2tcpip.h>
#pragma comment( lib, "Ws2_32.lib" )
#include <d3d9.h>
#pragma comment(lib, "d3d9.lib")
#include <d3dx9.h>
#pragma comment(lib, "d3dx9.lib")
#include <detours.h>
#pragma comment(lib, "detours.lib")
using namespace std;
D3DCOLOR RED = D3DCOLOR_ARGB(255, 255, 0, 0);
typedef HRESULT(__stdcall* EndScene) (IDirect3DDevice9*);
EndScene EndScene_orig;
HRESULT __stdcall EndScene_hook(IDirect3DDevice9* pDevice)
{
// D3DRECT rec = { 100,100,200,200 };
// pDevice->Clear(1, &rec, D3DCLEAR_TARGET, RED, 0, 0);
// MessageBoxA(0, "We made it here...2", "", 0); // <<<<----- This function is called over and over when not commented.
return EndScene_orig(pDevice);
}
void InitHook()
{
HWND game_window = FindWindow(NULL, _T("Skinned Mesh"));
auto d3dpp = D3DPRESENT_PARAMETERS{};
auto d3d = Direct3DCreate9(D3D_SDK_VERSION);
if (d3d)
{
d3dpp.BackBufferCount = 1;
d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.hDeviceWindow = game_window;
d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
d3dpp.BackBufferFormat = D3DFMT_R5G6B5;
d3dpp.Windowed = TRUE;
IDirect3DDevice9* Device;
if (SUCCEEDED(d3d->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, game_window, D3DCREATE_HARDWARE_VERTEXPROCESSING, &d3dpp, &Device)))
{
// MessageBoxA(0, "We made it here...", "", 0);
DWORD* pVTable = *reinterpret_cast<DWORD**>(Device);
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
EndScene_orig = (EndScene)pVTable[42];
DetourAttach(&(LPVOID&)pVTable[42], (PBYTE)EndScene_hook);
DetourTransactionCommit();
}
}
}
void SetupConsole()
{
AllocConsole();
freopen("CONOUT$", "wb", stdout);
freopen("CONOUT$", "wb", stderr);
freopen("CONIN$", "rb", stdin);
SetConsoleTitle("CSGOHAX");
}
BOOL APIENTRY DllMain(HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
SetupConsole();
CreateThread(0, 0, (LPTHREAD_START_ROUTINE)InitHook, 0, 0, NULL);
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
It has to be something simple that i just can't see as a problem..
I figured it out, reversed the binary in IDA, found the module address and the EndScene function aswell as its address, calculated the offset. Then used ollydbg and found the function again, made a signature from it, now i can find it dynamically using a signature scanning function.
So i can get the function address with this signature.
DWORD dwEndScene = FindPattern("d3d9.dll",
"\x6A\x18\xB8\x00\x00\x00\x00\xE8\x00\x00\x00\x00\x8B\x7D\x08\x8B\xDF\x8D\x47\x04\xF7\xDB\x1B\xDB\x23\xD8\x89\x5D\xE0\x33\xF6\x89\x75\xE4\x39\x73\x18\x75\x73",
"xxx????x????xxxxxxxxxxxxxxxxxxxxxxxxxxx");
Then i just detour the function
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
EndScene_orig = (oEndScene)(dwEndScene);
DetourAttach(&(LPVOID&)EndScene_orig, EndScene_hook);
This is much easier than trying to find the function in the V-Table using a dummy device as i was before.
Related
I am trying to hook a user-defined function. (via DLL injection and inline function hooking)
To do that, I need to get the address of the function to hook in process memory.
I tried various methods to find the address, and finally came up with the equation below.
(offset) = (Address of function in EXE file) - (Image base of EXE file)
(Address of function in process memory) = (GetModuleHandle(NULL)) + (offset)
However, I am not sure if this equation always holds. (For example, when DLL Relocation occurs, I am worried that this equation may be wrong.)
In conclusion, I want to know whether this equation always holds. And if not, I'd like to know how to fix this equation.
(This article has been translated by Google Translate.)
< testwinapi / main.cpp >
#include <stdio.h>
#include <Windows.h>
void capture(HBITMAP* canvas);
int APIENTRY WinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPSTR lpCmdLine, _In_ int nShowCmd) {
while(1) {
HBITMAP canvas;
capture(&canvas);
Sleep(2000);
}
return 0;
}
void capture(HBITMAP* canvas) {
RECT srcRect;
HWND hSrcWnd;
HDC hSrcDC, hDestDC;
hSrcWnd = GetDesktopWindow();
hSrcDC = GetDC(hSrcWnd);
GetWindowRect(hSrcWnd, &srcRect);
int SrceenWidth = srcRect.right - srcRect.left;
int SrceenHeight = srcRect.bottom - srcRect.top;
hDestDC = CreateCompatibleDC(hSrcDC);
*canvas = CreateCompatibleBitmap(hSrcDC, SrceenWidth, SrceenHeight);
SelectObject(hDestDC, *canvas);
for (int y = 0; y < SrceenHeight; y += 50) {
BitBlt(hDestDC, 0, y, SrceenWidth, 50, hSrcDC, 0, y, SRCCOPY);
Sleep(2);
}
ReleaseDC(hSrcWnd, hSrcDC);
DeleteDC(hDestDC);
}
< testdll / dllmain.cpp >
#include "pch.h"
DWORD WriteLog(LPCTSTR format, ...);
void MyCapture(HBITMAP* canvas);
void(*originFunc)(HBITMAP*) = reinterpret_cast<void(*)(HBITMAP*)>(0x941880); //Address of function in process memory
DWORD WriteLog(LPCTSTR lpszFormat, ...) {
TCHAR szLog[512];
DWORD dwCharsWritten;
va_list args;
va_start(args, lpszFormat);
_vstprintf_s(szLog, 512, lpszFormat, args);
va_end(args);
WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), szLog, _tcslen(szLog), &dwCharsWritten, NULL);
return dwCharsWritten;
}
void MyCapture(HBITMAP* canvas) {
WriteLog(TEXT("Function called : capture(0x%X)\n"), (DWORD)canvas);
return originFunc(canvas);
}
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {
if (DetourIsHelperProcess())
return TRUE;
switch (ul_reason_for_call) {
case DLL_PROCESS_ATTACH:
AllocConsole();
DetourRestoreAfterWith();
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourAttach(&(PVOID&)originFunc, MyCapture);
DetourTransactionCommit();
break;
case DLL_PROCESS_DETACH:
FreeConsole();
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourDetach(&(PVOID&)originFunc, MyCapture);
DetourTransactionCommit();
break;
}
return TRUE;
}
< testdll / pch.cpp >
#include "pch.h"
< testdll / pch.h >
#ifndef PCH_H
#define PCH_H
#include "framework.h"
#include <stdio.h>
#include <stdarg.h>
#include <tchar.h>
#include <detours.h>
//MS Detours library
//Can be downloaded from NuGet Package Manager
#endif
< testdll / framework.h >
#pragma once
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
< DLL Injector >
https://github.com/DarthTon/Xenos/releases/latest
After injecting 'testdll.dll' into 'testwinapi.exe', I want to be able to monitor the 'capture' function call. (Because the 'capture' function is reconstructed by reverse engineering, it is assumed that there is no source code for 'testwinapi.exe')
Module relocation occurs as a whole. Individual sections are never moved with respect to the image base. The offsets (RVA) of each section are hardcoded in the module header.
For example:
# Name VirtSize RVA PhysSize Offset
1 .text 000C44C1 00001000 000C4600 00000800
2 .data 00000FEC 000C6000 00000E00 000C4E00
3 .rsrc 00000520 000C7000 00000600 000C5C00
4 .reloc 0000B098 000C8000 0000B200 000C6200
These sections are loaded at specified RVA offsets, regardless of image base address. There's also the implicit "header" section with RVA 0 and size 0x1000, which is why the first section starts at 0x1000. Note that RVA offset != file offset.
So yes, given some known image base and an address inside of it, the offset of that address from the image base will remain constant.
This allows 64-bit code to employ RIP-relative addressing into the .data section, for example, which saves a fixup.
As none of you already know, I am quite fed up with DirectX at the moment. I have tried and tried, and no matter what I do, I cannot seem to get any hooks to work. I have scoured the web and studied hooks; I have combined bits of code together to scrap together my own hook; I have flat out plagiarized hooks to find out how they worked; I have even written a few from scratch. However, I cannot seem to get one to work. I'm trying to make a simple D3D mod-menu for CrossFire. What I have tried:
Hooking via VTable [had issues with getting a device pointer]
Hooking via pattern + mask scanning, etc and detours [unsure how to get a pattern, and cannot find one that works reliably for win10]
Creating a dummy device to get the addresses, etc, etc [caused an immediate shut-down of the game (detected)]
No matter what I do, the menu either flat out refuses to appear once programmed into the detoured EndScene, I get shut-down, I crash, or nothing happens.
Are there any good starter materials with sample code that I can learn from, as well as get this off the ground?
I already have the hack menu programmed, the variables set, the features programmed, the DllMain, the dependencies, you name it. All I need is to get a proper hook working - the only one I got to work had a weird bug where text drawing in EndScene & wall-hack in DrawIndexedPrimitive didn't work.
This is a large amount of code for a SO answer but here we go.
Get correct window
Create a dummy device
Get address of endscene from vtable
Do a standard x86 trampoline hook
Inside hook do whatever initialize stuff you need to
Get a copy of the correct device pointer
Draw stuff
call original function with correct device pointer
#pragma comment(lib, "d3d9.lib")
#pragma comment(lib, "d3dx9.lib")
#include <windows.h>
#include <d3d9.h>
#include <d3dx9.h>
bool Hook(char* src, char* dst, int len)
{
if (len < 5) return false;
DWORD curProtection;
VirtualProtect(src, len, PAGE_EXECUTE_READWRITE, &curProtection);
memset(src, 0x90, len);
uintptr_t relativeAddress = (uintptr_t)(dst - src - 5);
*src = (char)0xE9;
*(uintptr_t*)(src + 1) = (uintptr_t)relativeAddress;
DWORD temp;
VirtualProtect(src, len, curProtection, &temp);
return true;
}
char* TrampHook(char* src, char* dst, unsigned int len)
{
if (len < 5) return 0;
// Create the gateway (len + 5 for the overwritten bytes + the jmp)
char* gateway = (char*)VirtualAlloc(0, len + 5, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
// Put the bytes that will be overwritten in the gateway
memcpy(gateway, src, len);
// Get the gateway to destination addy
uintptr_t gateJmpAddy = (uintptr_t)(src - gateway - 5);
// Add the jmp opcode to the end of the gateway
*(gateway + len) = (char)0xE9;
// Add the address to the jmp
*(uintptr_t*)(gateway + len + 1) = gateJmpAddy;
// Place the hook at the destination
if (Hook(src, dst, len))
{
return gateway;
}
else return nullptr;
}
typedef HRESULT(APIENTRY* tEndScene)(LPDIRECT3DDEVICE9 pDevice);
static HWND window;
BOOL CALLBACK EnumWindowsCallback(HWND handle, LPARAM lParam)
{
DWORD wndProcId;
GetWindowThreadProcessId(handle, &wndProcId);
if (GetCurrentProcessId() != wndProcId)
return TRUE; // skip to next window
window = handle;
return FALSE; // window found abort search
}
HWND GetProcessWindow()
{
window = NULL;
EnumWindows(EnumWindowsCallback, NULL);
return window;
}
bool GetD3D9Device(void** pTable, size_t Size)
{
if (!pTable)
return false;
IDirect3D9* pD3D = Direct3DCreate9(D3D_SDK_VERSION);
if (!pD3D)
return false;
IDirect3DDevice9* pDummyDevice = NULL;
// options to create dummy device
D3DPRESENT_PARAMETERS d3dpp = {};
d3dpp.Windowed = false;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.hDeviceWindow = GetProcessWindow();
HRESULT dummyDeviceCreated = pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, d3dpp.hDeviceWindow, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &pDummyDevice);
if (dummyDeviceCreated != S_OK)
{
// may fail in windowed fullscreen mode, trying again with windowed mode
d3dpp.Windowed = !d3dpp.Windowed;
dummyDeviceCreated = pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, d3dpp.hDeviceWindow, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &pDummyDevice);
if (dummyDeviceCreated != S_OK)
{
pD3D->Release();
return false;
}
}
memcpy(pTable, *reinterpret_cast<void***>(pDummyDevice), Size);
pDummyDevice->Release();
pD3D->Release();
return true;
}
void DrawFilledRect(int x, int y, int w, int h, D3DCOLOR color, IDirect3DDevice9* dev)
{
D3DRECT BarRect = { x, y, x + w, y + h };
dev->Clear(1, &BarRect, D3DCLEAR_TARGET | D3DCLEAR_TARGET, color, 0, 0);
}
bool bInit = false;
tEndScene oEndScene = nullptr;
LPDIRECT3DDEVICE9 pD3DDevice = nullptr;
void* d3d9Device[119];
HRESULT APIENTRY hkEndScene(LPDIRECT3DDEVICE9 pDevice)
{
if (bInit == false)
{
pD3DDevice = pDevice;
bInit = true;
}
//draw stuff here like so:
DrawFilledRect(200, 200, 200, 200, D3DCOLOR_ARGB(255, 255, 0, 0), pDevice);
return oEndScene(pDevice);
}
DWORD WINAPI Init(HMODULE hModule)
{
if (GetD3D9Device(d3d9Device, sizeof(d3d9Device)))
{
oEndScene = (tEndScene)TrampHook((char*)d3d9Device[42], (char*)hkEndScene, 7);
}
return 0;
}
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
{
CloseHandle(CreateThread(nullptr, 0, (LPTHREAD_START_ROUTINE)Init, hModule, 0, nullptr));
}
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
Credits to me, Broihon, Solaire & 0xDEC0DE for this barebones d3d9 endscene hook
I started to lean c++ and directx11 a few days back.
So I am no expert at it. .Please be kind enough to explain me why it had occurred ...
I created the window and stuff correctly.Even the Swapchain initializtion proceeded as expected.But I am stuck at render Targetview Initializtion...
When ever i debug it gives me the following error
dxgiDevice 0x008959ac <Information not available, no symbols loaded for d3d11.dll> IDXGIDevice
I dont know what am I doing wrong here.I have included Static libraries(dxgi.lib
d3dx11.lib
d3d11.lib
dxguid.lib
D3DCompiler.lib) and linked correctly the header files and libraries as well..
The error seems to arise from this line
SwapChain->GetBuffer(0,__uuidof(ID3D11Texture2D),(LPVOID*)(&backBuffer));
I dont know what to do..It has gotten me really frustrated.
Please do help me out here..I will be very thank full
Thanks
Here is the full code
#include <Windows.h>
#include <windowsx.h>
#include <D3D11.h>
#include <D3DX11.h>
#include <D3DX10.h>
using namespace std;
LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);
bool InitWindowClass(HINSTANCE hinst,int shw,HWND * _hwnd,WNDCLASSEX * exClass);
RECT windowWidth = {0,0, 1000,768};
int WINAPI WinMain(HINSTANCE inst,HINSTANCE previnst,LPSTR cmdLine,int show)
{
// Window Params
HWND hwnd;
WNDCLASSEX exClass;
MSG msg;
// Iniitaliztion
SecureZeroMemory(&hwnd,sizeof(HWND));
SecureZeroMemory(&exClass,sizeof(exClass));
SecureZeroMemory(&msg,sizeof(MSG));
// Directx 11 Functionalities
#pragma region Create the device
D3D_FEATURE_LEVEL featureLevels[4] = {D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_10_1 , D3D_FEATURE_LEVEL_10_0 , D3D_FEATURE_LEVEL_9_1};
D3D_FEATURE_LEVEL feature_LEVEL;
ID3D11Device * d3dDevice = 0;
ID3D11DeviceContext * d3dContext = 0;
HRESULT hr = D3D11CreateDevice(0,
D3D_DRIVER_TYPE_HARDWARE,
0,
0, // No flags
featureLevels,4,
D3D11_SDK_VERSION,
&d3dDevice,
&feature_LEVEL,&d3dContext);
if(FAILED(hr))
{
MessageBox(hwnd,L"FAiled TO CREATE DEVICE",L"ERROR",0);
}
#pragma endregion
#pragma region Multisampling
UINT multisampleQuality;
d3dDevice->CheckMultisampleQualityLevels(DXGI_FORMAT_B8G8R8A8_UNORM,4,&multisampleQuality);
#pragma endregion
#pragma region DescribeSwapChain
DXGI_SWAP_CHAIN_DESC swapDesc;
// Allocate Mommory
SecureZeroMemory(&swapDesc,sizeof(DXGI_SWAP_CHAIN_DESC));
swapDesc.BufferDesc.Width = 1000;
swapDesc.BufferDesc.Height = 768;
swapDesc.BufferDesc.RefreshRate.Numerator= 60;
swapDesc.BufferDesc.RefreshRate.Denominator = 1;
swapDesc.BufferDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
swapDesc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
swapDesc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
//MSAA
swapDesc.SampleDesc.Count = 4;
swapDesc.SampleDesc.Quality = multisampleQuality;
//BackBuffer
swapDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapDesc.BufferCount = 1;
swapDesc.OutputWindow = hwnd;
swapDesc.Windowed = true;
swapDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
swapDesc.Flags = 0;
#pragma endregion
#pragma region CreateSwapChain
#pragma region Obtain DXGIFactory
// DXGIFactory >> DXGIAdaptor >> DXGIDevice
// Get the DXGI device
IDXGIDevice * dxgiDevice = 0;
d3dDevice->QueryInterface(__uuidof(IDXGIDevice),(void**)&dxgiDevice);
// Obtain DXGIAdaptor
IDXGIAdapter * dxgiAdaptor = 0;
dxgiDevice->GetParent(__uuidof(IDXGIAdapter),(void**)&dxgiAdaptor);
IDXGIFactory * dxgiFactory = 0;
dxgiAdaptor->GetParent(__uuidof(IDXGIFactory),(void**)&dxgiFactory);
#pragma endregion
IDXGISwapChain * SwapChain = 0;
SecureZeroMemory(&SwapChain,sizeof(IDXGISwapChain));
dxgiFactory->CreateSwapChain(d3dDevice,&swapDesc,&SwapChain);
dxgiAdaptor->Release();
dxgiDevice->Release();
dxgiFactory->Release();
#pragma endregion
#pragma region Create Render Target View
ID3D11RenderTargetView * RenderTarget = 0;
ID3D11Texture2D * backBuffer = 0;
SwapChain->GetBuffer(0,__uuidof(ID3D11Texture2D),(LPVOID*)(&backBuffer));
d3dDevice->CreateRenderTargetView(backBuffer,NULL,&RenderTarget);
backBuffer->Release();
#pragma endregion
if(InitWindowClass(inst,show,&hwnd,&exClass))
{
while(msg.message != WM_QUIT)
{
if(PeekMessage(&msg,hwnd,0,0,PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}else{
// Update Sequences
}
}
}
return msg.wParam;
}
// Initialize and show the Window
bool InitWindowClass(HINSTANCE hinst,int shw,HWND * _hwnd,WNDCLASSEX * exClass)
{
HWND hwnd2 ;
SecureZeroMemory(&hwnd2,sizeof(HWND));
exClass->cbSize = sizeof(WNDCLASSEX);
exClass->hCursor = LoadCursor(0,IDC_ARROW);
exClass->hInstance = hinst;
exClass->lpfnWndProc = WndProc;
exClass->lpszClassName = L"DX_Test";
exClass->lpszMenuName = L"Test";
exClass->hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
RegisterClassEx(exClass);
AdjustWindowRect(&windowWidth,WS_OVERLAPPEDWINDOW,false);
(*_hwnd) = CreateWindowEx(0,L"DX_Test",L"Test",WS_OVERLAPPEDWINDOW,500,200,windowWidth.left,windowWidth.top,NULL,NULL,hinst,0);
ShowWindow((*_hwnd),shw);
UpdateWindow(*_hwnd);
return true;
}
// Message Loop
LRESULT CALLBACK WndProc(HWND hwnd,UINT msg,WPARAM wparam,LPARAM lparam)
{
switch (msg)
{
case WM_LBUTTONDBLCLK:
MessageBox(hwnd,L"Prressed Button 1",L"Mouse 1",0);
return 0;
break;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
break;
case WM_KEYDOWN:
if(wparam == VK_ESCAPE)
DestroyWindow(hwnd);
return 0;
}
return DefWindowProc(hwnd,msg,wparam,lparam);
}
The "error message" you're talking about comes from the VS debugger: all it is telling you is that it doesn't have any debugging symbols for d3d11.dll. In other words this is not your problem - it's a red herring.
To solve the problem, you need some error checking. IDXGISwapChain::GetBuffer returns a HRESULT, which you should check for errors, e.g.:
HRESULT res = SwapChain->GetBuffer(...);
if (!SUCCEEDED(res))
{
std::cerr << "Error getting buffer from swap chain: " << std::hex << res << std::endl;
}
You can then check the result against the values in this set of documentation to find out specifically what the error was.
Note that you should probably do similar things for a lot of your other DirectX calls as well.
And I can't figure out why. My code:
#include <windows.h>
#include <commctrl.h>
#include <cstdio>
#include <stdarg.h>
#include <string>
#include <cmath>
#include <vector>
#include "resources.hpp"
using std::string;
using std::vector;
struct undostruct{
/* add later */};
char buffer[2048];
HWND statusbar;
HINSTANCE hinst;
vector<undostruct> undo;
void show_error(const char* format,...){
va_list args;
va_start(args,format);
vsprintf(buffer,format,args);
va_end(args);
MessageBox(NULL,buffer,"ERROR",MB_OK);}
HWND create_tooltip(HWND parent,char* tip,unsigned uid,unsigned extraflags=0){
HWND tt=CreateWindowEx(WS_EX_TOPMOST,TOOLTIPS_CLASS,NULL,WS_POPUP|TTS_NOPREFIX|TTS_ALWAYSTIP,0,0,0,0,parent,NULL,NULL,NULL);
SetWindowPos(tt,HWND_TOPMOST,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE);
TOOLINFO ti;
ti.cbSize=sizeof(TOOLINFO);
ti.uFlags=TTF_SUBCLASS|extraflags;
ti.hwnd=parent;
ti.hinst=NULL;
ti.uId=uid;
ti.lpszText=tip;
GetClientRect(parent,&ti.rect);
SendMessage(tt,TTM_ADDTOOL,0,(LPARAM)(LPTOOLINFO)&ti);
return tt;}
LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);
class Font{
private:
HFONT hfont;
public:
Font(const char* fname){
hfont=CreateFont(0,0,0,0,FW_NORMAL,false,false,false,DEFAULT_CHARSET,OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,DEFAULT_PITCH,fname);}
~Font(){
DeleteObject(hfont);}
operator HFONT(){
return hfont;}}courier("Courier New");
bool get_filename(char* fname,int len,HWND hwnd,bool save){
OPENFILENAME ofn;
ZeroMemory(&ofn,sizeof(OPENFILENAME));
ofn.lStructSize=sizeof(OPENFILENAME);
ofn.hwndOwner=hwnd;
ofn.lpstrFilter="Text Files (*.txt)\0*.txt\0All Files (*.*)\0*.*\0\0";
ofn.lpstrFile=fname;
ofn.nMaxFile=len;
ofn.lpstrTitle="Text Editor";
ofn.Flags=OFN_FILEMUSTEXIST|OFN_HIDEREADONLY;
if(save){
return GetSaveFileName(&ofn);}
else{
return GetOpenFileName(&ofn);}}
int WINAPI WinMain(HINSTANCE hprev,HINSTANCE hInst,LPSTR cmdline,int cmdshow){
WNDCLASSEX wcex;
//HACCEL haccel=LoadAccelerators(hInst,MAKEINTRESOURCE(ACCELS));
HWND hwnd;
MSG msg;
hinst=hInst;
//Register the window
wcex.cbSize=sizeof(WNDCLASSEX);
wcex.style=CS_HREDRAW|CS_VREDRAW;
wcex.lpfnWndProc=WndProc;
wcex.cbClsExtra=0;
wcex.cbWndExtra=0;
wcex.hInstance=hinst;
wcex.hIcon=NULL;
wcex.hCursor=NULL;
wcex.hbrBackground=(HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName=MAKEINTRESOURCE(MAINMENU);
wcex.lpszClassName="ImageEditor";
wcex.hIconSm=NULL;
if(!RegisterClassEx(&wcex)){
show_error("Error %i: Failed to register the window.",GetLastError());
return -1;}
//Create the window
hwnd=CreateWindow("ImageEditor","Image Editor",WS_VISIBLE|WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,NULL,NULL,hinst,NULL);
if(!hwnd){
show_error("Error %i: Failed to create the window.",GetLastError());
return -2;}
//Show/Update the window
ShowWindow(hwnd,cmdshow);
UpdateWindow(hwnd);
//Initialize common controls
/*INITCOMMONCONTROLSEX iccex;
iccex.dwICC=ICC_WIN95_CLASSES;
iccex.dwSize=sizeof(INITCOMMONCONTROLSEX);
InitCommonControlsEx(&iccex);*/
//Go into the main program loop
while(GetMessage(&msg,NULL,0,0)){
//if(!TranslateAccelerator(hwnd,haccel,&msg)){
TranslateMessage(&msg);
DispatchMessage(&msg);}//}
return msg.wParam;}
LRESULT CALLBACK WndProc(HWND hwnd,UINT msg,WPARAM wparam,LPARAM lparam){
static int sizes[]={260,330,420,520};
switch(msg){
case WM_CREATE:
statusbar=CreateWindow(STATUSCLASSNAME,"",WS_CHILD|WS_BORDER|WS_VISIBLE,-100,-100,10,10,hwnd,NULL,hinst,NULL);
if(!statusbar){
show_error("Error %i: Failed to create the statusbar.",GetLastError());}
//Description|Characters|Size|Lines|Line|Column
SendMessage(statusbar,SB_SETPARTS,sizeof(sizes),(LPARAM)sizes);
break;
case WM_QUIT:
DestroyWindow(hwnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_COMMAND:
//switch(LOWORD(wparam)){}
//break;
default:
return DefWindowProc(hwnd,msg,wparam,lparam);}
return 0;}
Also, my compiler doesn't recognize INITCOMMONCONTROLSEX when it should, which is commented out near the end of WinMain.
The most likely bug in this code is that you need to run InitCommonControls BEFORE creating a window. And forget that InitCommonControlsEx() code, you'll be better with a plain old InitCommonControls.
Remember to check every function's return value and use GetLastError().
Also, you're trying to reinvent the wheel and instead of rolling out your own window creating procedure I suggest you to take a look at how others do it, or even use WTL, it's not that difficult.
I've downloaded and compiled the Microsoft detouring library. Inside my project I've included the header file and added the .lib file as a dependency. Everything compiles without errors. Now I've been trying to detour DrawText, but for some reason that detoured function doesn't get called at all. Similiarly I tried detouring the Sleep function and that worked as intended and the function I detoured to was called.
I'm not very well-versed in the business of API programming nor any other low level activities. I suspect it might have something to do with the fact that I'm trying to do this inside a console application instead of having the detouring done inside a DLL. I just find it strange that it would be able to detour Sleep in that case.
Is there something wrong with my approach or does the fault lie in the code?
#include <windows.h>
#include <stdio.h>
#include "detours.h"
int ( WINAPI *Real_DrawText )(HDC a0, LPCSTR a1, int a2, LPRECT a3, UINT a4) = DrawTextA;
int Mine_DrawText(HDC hdc, LPCSTR text, int nCount, LPRECT lpRect, UINT uOptions)
{
printf("TEST");
return Real_DrawText(hdc, text, nCount, lpRect, uOptions);
}
int main(int argc, char **argv)
{
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourAttach(&(PVOID&)Real_DrawText, Mine_DrawText);
DetourTransactionCommit();
printf("Calling Sleep\n");
Sleep(1000);
printf("Second callout");
Sleep(5000);
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourDetach(&(PVOID&)Real_DrawText, Mine_DrawText);
DetourTransactionCommit();
return 0;
}
Based on your code-example, it seems you're only detouring your own process. Therefore detouring DrawText doesn't output anything. Perhaps, you need to inject your code to desired target's process memory and detour the API call from there. For example, you can create system wide CBT hook which works kind of a.. launch point to your detouring needs. Something like this, to point you out a direction:
LRESULT CALLBACK CBTProcedure(int nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode < 0)
return CallNextHookEx(g_hHook, nCode, wParam, lParam);
else if (!g_pClient)
return 0;
HWND hWnd = (HWND)wParam;
if (!hWnd)
return 0;
switch (nCode) {
case HCBT_ACTIVATE:
/** Here, you can check up against the handle to see,
* if the target window is the one you're looking for...
*
*/
if (!g_pClient->IsRegisteredWindow(hWnd))
if (g_pClient->RegisterWindow(hWnd)) {
}
break;
case HCBT_DESTROYWND:
if (g_pClient->IsRegisteredWindow(hWnd))
g_pClient->UnregisterWindow(hWnd);
break;
}
return 0;
}
bool __0XYOUROWN_API InstallHook()
{
// Call this one from your main process; set's up the system-wide hook.
g_hHook = SetWindowsHookEx(WH_CBT, (HOOKPROC)CBTProcedure, g_hInstance, 0);
/** #pragma data_seg("Shared")
* HHOOK g_hHook = NULL;
* #pragma data_seg()
*/
return g_hHook != NULL;
}
/** The actual DLL...
*
*
*/
BOOL APIENTRY DllMain(HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
switch (ul_reason_for_call) {
case DLL_PROCESS_ATTACH:
g_hInstance = (HINSTANCE)hModule;
if (::GetModuleHandle(_T("THEDESIREDMODULE.EXE")) != NULL) {
g_pClient = new Client();
if (g_pClient) {
InitializeCriticalSection(&g_CriticalSection); // You can setup a critic. sec. for later synchronization...
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourAttach(&(PVOID&)Real_DrawTextW, Mine_DrawTextW);
DetourTransactionCommit();
}
}
break;
case DLL_THREAD_ATTACH: break;
case DLL_THREAD_DETACH: break;
case DLL_PROCESS_DETACH:
if (::GetModuleHandle(_T("THEDESIREDMODULE.EXE")) != NULL) {
if (g_pClient) {
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourDetach(&(PVOID&)Real_DrawTextW, Mine_DrawTextW);
DetourTransactionCommit();
delete g_pClient;
g_pClient = NULL;
}
}
break;
}
}
It seems you're assuming printf() will call DrawText(). It won't. DrawText() is a GDI function. printf() goes to WriteConsole(). These don't intermix. "Console Windows" are quite unlike all other windows. This distinction is a fundamental architectural one; they're even managed by separate kernel components.
Only a side note: EasyHook - The reinvention of Windows API Hooking is an open source (LGPL) project developing a successor to Detours. It is quite mature already.