I am writing a DLL that gets injected into a game in order to play around with some reverse engineering. For a while I was able to successfully inject, eject and reinject as I made changes to the program. I'm using FreeLibraryAndExitThread
to unload.
After adding XInput to the program so I could catch user input, the game crashes with an access violation when I call FreeLibraryAndExitThread
. Going from this post, I'm guessing that using XInput is leaving something 'live' in the program when I go to unload, and that's what's causing the crash. I'm honestly at a loss as to how to fix this.
Here's the code that's crashing the program on exit:
XINPUT_STATE state;
ZeroMemory(&state, sizeof(XINPUT_STATE));
//The problematic line of code
bool gamepad = XInputGetState(0, &state) == ERROR_SUCCESS;
WORD buttonsHeld = state.Gamepad.wButtons;
WORD buttonsPressed = (~previousButtonState) & state.Gamepad.wButtons;
WORD buttonsReleased = previousButtonState & (~state.Gamepad.wButtons);
When I remove the call to XInputGetState
, everything works just fine and I'm able to unload the DLL without crashing.
And here's how I'm calling for the program to unload and exit
FreeLibraryAndExitThread(hDLL, 0);
Where hDLL
is the argument hinstDLL
from DllMain
. I've also tried GetModuleHandleEx
instead of using hinstDLL
.
My guess is either:
Using
XInputGetState
makes my program load a second DLL forXInput
, orXInputGetState
is creating some sort of reference to my DLL when called and when I remove my DLL, it's trying to access memory that's no longer there.
EDIT: I did a bit of digging and the problem seems to be that adding the call to XInputGetState
causes my DLL to load XINPUT1_4.dll
. I tried using FreeLibrary
to unload it but that isn't working.
EDIT: I narrowed it down some more - it turns out that the access violation is being caused by some thread within the game trying to return to part of XINPUT1_4.dll's code, which is unloaded, making it crash. And I have no clue how to fix that.
Final Edit: It was a simple fix, I had to call LoadLibrary(L"XINPUT1_4.dll")
for the DLL that was causing the issue.
Here's the solution:
The problem was that invoking
XInputGetState
caused my DLL to automatically loadXINPUT1_4.dll
, and when I called FreeLibraryAndExitThread, my DLL unloading forced the XInput DLL to unload as well. Code within the program (probably from a thread in XInput 1.4) attempted to execute code that was no longer there, causing an access violation.So the solution was simply to call
LoadLibrary(L'XINPUT1_4.dll')
after I initialize my DLL's thread so that when my DLL is unloaded, the XInput DLL stays in memory because theLoadLibrary
increases the reference count.(When a DLL's reference count reaches 0, it unloads. It is initialized as 1 when you first load it, LoadLibrary increments it by 1, and calling FreeLibraryAndExitThread decrements it by 1. So when all is said and done, its reference count is above 0 and it remains in memory as my DLL is unloaded)