Skip to content

Commit

Permalink
devicelost: fix using more generic approach
Browse files Browse the repository at this point in the history
Apparently my original fix only worked for me, because there are
multiple sets of Reset calls, and I've only patched one of them.

To avoid going through all the executables again, I decided to just
detour the Reset function. Idealy we would need to do something like
nmlgc/ProxyDLLs, but this should work for now.

I tried copying the vtable, but it turned out to be a bad idea, because
the size of vtable is unknown. The only other way, besides creating a
proxy object, is editing the vtable directly.
  • Loading branch information
DankRank committed Jul 17, 2017
1 parent 0ecafb0 commit cb3404c
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 16 deletions.
75 changes: 61 additions & 14 deletions thcrap_tsa/src/devicelost.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,40 +10,87 @@
#include <thcrap.h>
#include "thcrap_tsa.h"

// HRESULT values from d3d9.h
#define FACILITY_D3D 0x88760000
#define D3D_OK 0
#define D3DERR_DRIVERINTERNALERROR (FACILITY_D3D|2087)
#define D3DERR_DEVICELOST (FACILITY_D3D|2152)
#define D3DERR_DEVICENOTRESET (FACILITY_D3D|2153)

int BP_devicelost(x86_reg_t *regs, json_t *bp_info) {
// Parameters
// ----------
void ***d3dd9 = *(void ****)json_object_get_register(bp_info, regs, "d3dd9");
void *presParams = (void *)json_object_get_immediate(bp_info, regs, "pres_params");
// ----------
// vtable indeices
#define D3DD9_TESTCOOPERATIVELEVEL 3
#define D3DD9_RESET 16
#define D3D9_CREATEDEVICE 16

// function no. 16 - Reset
int(__stdcall*d3dd9_Reset)(void***,void*) = (*d3dd9)[16];
// function no. 3 - TestCooperativeLevel
int(__stdcall*d3dd9_TestCooperativeLevel)(void***) = (*d3dd9)[3];
// original memeber function pointers
static int(__stdcall*orig_d3dd9_Reset)(void***, void*) = NULL;
static int(__stdcall*orig_d3d9_CreateDevice)(void***, UINT, int, void*, DWORD, void*, void****) = NULL;
static void***(__stdcall*orig_Direct3DCreate9)(UINT SDKVersion) = NULL;

for(;;){
switch (d3dd9_TestCooperativeLevel(d3dd9)) {
int __stdcall my_d3dd9_Reset(void*** that, void* pPresentationParameters) {
int(__stdcall*d3dd9_TestCooperativeLevel)(void***) = (*that)[D3DD9_TESTCOOPERATIVELEVEL];
int rv = D3D_OK;
for (;;) {
switch (d3dd9_TestCooperativeLevel(that)) {
case D3DERR_DEVICELOST:
// wait for a little
MsgWaitForMultipleObjects(0, NULL, FALSE, 10, QS_ALLINPUT);
break;
case D3DERR_DEVICENOTRESET:
d3dd9_Reset(d3dd9, presParams);
rv = orig_d3dd9_Reset(that, pPresentationParameters);
break;
default:
case D3DERR_DRIVERINTERNALERROR:
MessageBox(0, "Unable to recover from Device Lost error.", "Error", MB_ICONERROR);
// panic and return (will probably result in crash)
// [[fallthrough]]
case D3D_OK:
return 0;
return rv;
}
}
}

int __stdcall my_d3d9_CreateDevice(void*** that, UINT Adapter, int DeviceType, void* hFocusWindow, DWORD BehaviourFlags, void* pPresentationParameters, void**** ppReturnedDeviceInterface) {
int rv = orig_d3d9_CreateDevice(that, Adapter, DeviceType, hFocusWindow, BehaviourFlags, pPresentationParameters, ppReturnedDeviceInterface);
if (rv == D3D_OK && ppReturnedDeviceInterface && *ppReturnedDeviceInterface) {
if (!orig_d3dd9_Reset) {
void **d3dd9_vtable = **ppReturnedDeviceInterface;
orig_d3dd9_Reset = d3dd9_vtable[D3DD9_RESET];

DWORD oldProt;
VirtualProtect(&d3dd9_vtable[D3DD9_RESET], sizeof(void*), PAGE_EXECUTE_READWRITE, &oldProt);
d3dd9_vtable[D3DD9_RESET] = my_d3dd9_Reset;
VirtualProtect(&d3dd9_vtable[D3DD9_RESET], sizeof(void*), oldProt, &oldProt);
}
}
return rv;
}

void*** __stdcall my_Direct3DCreate9(UINT SDKVersion) {
if (!orig_Direct3DCreate9) return NULL;
void*** rv = orig_Direct3DCreate9(SDKVersion);
if (rv) {
if (!orig_d3d9_CreateDevice) {
void **d3d9_vtable = *rv;
orig_d3d9_CreateDevice = d3d9_vtable[D3D9_CREATEDEVICE];

DWORD oldProt;
VirtualProtect(&d3d9_vtable[D3D9_CREATEDEVICE], sizeof(void*), PAGE_EXECUTE_READWRITE, &oldProt);
d3d9_vtable[D3D9_CREATEDEVICE] = my_d3d9_CreateDevice;
VirtualProtect(&d3d9_vtable[D3D9_CREATEDEVICE], sizeof(void*), oldProt, &oldProt);
}
}
return rv;
}

void devicelost_mod_detour(void)
{
HMODULE hModule = GetModuleHandle(L"d3d9.dll");
if (hModule) {
orig_Direct3DCreate9 = GetProcAddress(hModule, "Direct3DCreate9");
detour_chain("d3d9.dll", 1,
"Direct3DCreate9", my_Direct3DCreate9, &orig_Direct3DCreate9,
NULL
);
}
}
3 changes: 1 addition & 2 deletions thcrap_tsa/thcrap_tsa.def
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,6 @@ EXPORTS
BP_th06_file_load
BP_th06_file_loaded

BP_devicelost

; Bounds
; ------
fn_for_bounds
Expand Down Expand Up @@ -110,3 +108,4 @@ EXPORTS
; TSA-specific detours
; --------------------
tsa_mod_detour
devicelost_mod_detour

0 comments on commit cb3404c

Please sign in to comment.