Winapi hook via mhook causes program crash or hang - c++

I am trying to hook StartDocW to intercept printing via mhook. I use AppInit_DLLs to load my library.
DLL code is simple:
#include <windows.h>
#include "mhook/mhook-lib/mhook.h"
using StartDocPtr = int(*)(HDC, const DOCINFO*);
StartDocPtr orig;
int HookedStartDocW(HDC hdc, const DOCINFO* lpdi) {
return orig(hdc, lpdi);
}
BOOL WINAPI DllMain(__in HINSTANCE, __in DWORD Reason, __in LPVOID) {
orig = (StartDocPtr)GetProcAddress(GetModuleHandle("gdi32"), "StartDocW");
switch (Reason)
{
case DLL_PROCESS_ATTACH:
Mhook_SetHook((PVOID*)&orig, &HookedStartDocW);
break;
case DLL_PROCESS_DETACH:
Mhook_Unhook((PVOID*)&orig);
break;
}
}
Hook is working and printing is done OK. But If I change HookStartDocW to following:
int HookedStartDocW(HDC hdc, const DOCINFO* lpdi) {
char buf[40];
GetModuleFileName(NULL, buf, 40);
return orig(hdc, lpdi);
}
Programs on printing will crash immediately. Even if I just leave char buf[40] and comment GetModuleHandle - program will hang. Why is this happening?
Moreover, if program crashes\hangs on printing (if I add anything besides return orig(hdc, lpdi)) - PC starts to behave very weirdly, refusing to run programs, etc. If I reboot it - Windows just endlessly spins on boot screen, the only way to bring it back to live - is to boot via liveCD and rename\delete my hook DLL.
Printing programs: Excel 2016, notepad.
Compiler - MSVC 2015, x64 release DLL compilation, using MBCS instead of unicode.

Your hook is declared wrong.
Look at the actual declaration of StartDocW() in Wingdi.h:
__gdi_entry WINGDIAPI int WINAPI StartDocW(__in HDC hdc, __in CONST DOCINFOW *lpdi);
You can ignore __gdi_entry. WINGDIAPI simply resolves to __declspec(dllimport). What is important in this declaration is the WINAPI.
Like almost all Win32 API functions, StartDocW() uses the __stdcall calling convention. The WINAPI macro resolves to __stdcall.
Your code does not specify any calling convention at all, so it uses your compiler's default, which is usually __cdecl instead. So you are mismanaging the call stack. That is why your code crashes.
You are also using DOCINFO when you should be using DOCINFOW instead. It is clear in your code that you are compiling for MBCS and not for UNICODE, so DOCINFO maps to DOCINFOA. You can't pass a DOCINFOA to StartDocW(), it expects a DOCINFOW instead.
You need to fix your declarations, eg:
#include <windows.h>
#include "mhook/mhook-lib/mhook.h"
using StartDocPtr = int (WINAPI *)(HDC, const DOCINFOW*);
StartDocPtr orig = nullptr;
int WINAPI HookedStartDocW(HDC hdc, const DOCINFOW* lpdi) {
//...
return orig(hdc, lpdi);
}
BOOL WINAPI DllMain(__in HINSTANCE, __in DWORD Reason, __in LPVOID) {
orig = (StartDocPtr) GetProcAddress(GetModuleHandle(TEXT("gdi32")), "StartDocW");
switch (Reason)
{
case DLL_PROCESS_ATTACH:
Mhook_SetHook((PVOID*)&orig, &HookedStartDocW);
break;
case DLL_PROCESS_DETACH:
Mhook_Unhook((PVOID*)&orig);
break;
}
}

Related

CreateThread in DLL Terminating Prematurely

I am trying to load a DLL from Console Application. The simple console application is shown below:
#include <iostream>
#include <windows.h>
int main(){
HMODULE handleDll = LoadLibraryA("C:\\Tools\\TestDLL.dll");
if (handleDll)
{
std::cout << "DLL Loaded at Address: " << handleDll << std::endl;
}
FreeLibrary(handleDll);
}
The DLL is supposed to a POP a MessageBox which it does but just flashes on the screen instead of waiting for user input. The DLL code is below:
// dllmain.cpp : Defines the entry point for the DLL application.
#include "pch.h"
#include <Windows.h>
DWORD WINAPI ThreadProc( __in LPVOID lpParameter )
{
MessageBox(NULL, L"Hi From The Thread!", L"Pop a Box!", MB_OK);
return 0;
}
extern "C" __declspec(dllexport)
VOID PopMessageBox()
{
DWORD ThreadID;
HANDLE handleThread;
handleThread = CreateThread(NULL, 0, ThreadProc, 0, 0, &ThreadID);
CloseHandle(handleThread);
}
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
PopMessageBox();
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
My question is..how do I make the code in the thread function fully execute without prematurely terminating or causing painful deadlocks? Apologies for my imperfect English and inexperience.
The reason is that you are doing something unsafe in your DllMain: you are calling CreateThread.
You are very limited in what you can do from within DllMain in response to a process attach, a fact that the documentation calls out:
There are significant limits on what you can safely do in a DLL entry point. See General Best Practices for specific Windows APIs that are unsafe to call in DllMain. If you need anything but the simplest initialization then do that in an initialization function for the DLL. You can require applications to call the initialization function after DllMain has run and before they call any other functions in the DLL.
The warning links you to "General Best Pratices" which, among other things, says to "[c]all CreateThread. Creating a thread can work if you do not synchronize with other threads, but it is risky."
Even without the risks associated with synchronizing with other threads, this code is flakey in other ways: for example, your main simply calls FreeLibrary and exits. The thread you had spawned in the DLL, which may literally be mid-execution, will have the code it's supposed to run unmapped. You're literally pulling the rug out from under it!

How to hook functions that aren't in the Win32 API?

I made a very simple program that create a windows and display "Random number is: [random number from 0 to 9]" in the top left corner. The function that display the number looks like this:
void DisplayThings(HDC hdc, HWND hWnd, int randomNum)
{
std::stringstream text;
text << "Random number is: " << randomNum;
TextOut(hdc, 0, 0, text.str().c_str(), text.str().length());
}
In OllyDBG, I found it at the address 0x11211A0:
Next, I made a dll that tries to detour the DisplayThings function with the help of Microsoft Detour, here is what the dll looks like:
#pragma comment(lib, "detours.lib")
#include <Windows.h>
#include <detours.h>
#include <tchar.h>
#include <sstream>
typedef void (*pDisplayThingsFunc)(HDC hdc, HWND hWnd, int randomNum);
void DisplayThingsFunc(HDC hdc, HWND hWnd, int randomNum)
{
printf("function is being detoured\n");
TextOut(hdc, 0, 20, L"detoured", 8);
}
pDisplayThingsFunc DisplayThingsFuncToDetour = (pDisplayThingsFunc)(0x11211A0);
BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved )
{
//DWORD *hiddenValueAdress = (DWORD*)(*(DWORD*)0x020FAB8);
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
AllocConsole();
freopen("CONOUT$", "w", stdout);
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourAttach(&(PVOID&)DisplayThingsFuncToDetour, DisplayThingsFunc);
DetourTransactionCommit();
break;
case DLL_PROCESS_DETACH:
FreeConsole();
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourDetach(&(PVOID&)DisplayThingsFuncToDetour, DisplayThingsFunc);
DetourTransactionCommit();
break;
}
return TRUE;
}
Once I inject the dll, the address get correctly replaced with a JMP to my new functions, but then something weird happens... The console keep printing "function is being detoured" but the TextOut function fails to display anything...
Any help would be appreciated!
The compiler is optimizing the code, because it deduced that it could safely do so for this function.
It is not exported.
It is not used with function pointers.
It is not used outside the scope that is analyzed. (Depends on compiler settings)
There is most likely only one caller (if there are more different callers with different settings it's less likely that arguments get optimized away).
You could change one of those things (for example by exporting the symbol, by assigning it to a function pointer etc..).
Or you could try to hook it as-is now.
First you need to deduce where the argument you are interested in is getting passed trough, which is most likely a register.
The easiest way to do this is to analyze the call to TextOut and trace the hdc argument back.
If you are lucky and it got optimized simply by making it fastcall, change the type of both your function and your function pointer to fastcall, and be done.
If you are not that lucky, you might have to grab it from an extra register with inline assembly.

Why does the DirectX Device Present hook not work in detours?

I am creating a hook which will allow to hook the Present method from the Direct X 9 device,
I do this as follow:
#include <windows.h>
#include <detours.h>
#include <iostream>
#include <d3d9.h>
#pragma comment( lib, "d3d9.lib" )
typedef HRESULT(PresentDef)(const RECT *pSourceRect, const RECT *pDestRect, HWND hDestWindowOverride, const RGNDATA *pDirtyRegion);
PresentDef* Real_Present;
PresentDef Mine_Present;
HRESULT Mine_Present(const RECT *pSourceRect, const RECT *pDestRect, HWND hDestWindowOverride, const RGNDATA *pDirtyRegion)
{
return Real_Present(pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion);
}
BOOL WINAPI DetoursInit(HINSTANCE, DWORD dwReason, LPVOID) {
switch (dwReason) {
case DLL_PROCESS_ATTACH:
LoadLibrary("d3d9.dll");
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
Real_Present = (PresentDef*)DetourFindFunction("d3d9.dll", "IDirect3DDevice9::Present");
DetourAttach(&(PVOID &)Real_Present, Mine_Present);
if (ERROR_SUCCESS != DetourTransactionCommit())
{
MessageBoxA(NULL, "Failed to Detour", "ERROR", 0);
break;
}
break;
case DLL_PROCESS_DETACH:
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourDetach(&(PVOID &)Real_Present, Mine_Present);
DetourTransactionCommit();
break;
}
return TRUE;
}
But every time I do this, I get the Failed to detour message.
Is there any way to detour pure virtual members with microsoft detours?
I'm not going to give any code examples. This is an advanced topic, and you should do the research yourself.
You can download the source code of DSFix for Dark Souls and look through it. This will give you a good starting point. link: http://blog.metaclassofnil.com/?tag=dsfix
The basic idea is that you are detouring a "COM-object" not a "pure function". Consider 'd3d9::IDirect3DDevice9::Present' vs 'd3d9::Present'.
In the latter case, you would have no problem detouring, using your method. Detours knows the entry-point/address of the d3d9.dll, which is 'd3d9' and the entry-point/address and the function Present() which is 'd3d9::Present'.
However, since Direct3D uses the 'COM model' it will need some way of referring to the 'COM object', in this case 'IDirect3DDevice9' (the interface for the Direct3D device). You do this by creating your own detoured Direct3DDevice9 object through the function Direct3DCreate9 which is not a 'COM object' but creates the 'COM object' you need to reference the Present() function. Therefore you should make a 'd3d9::Direct3DCreate9' detour which will create a device object (lets call it device9), which you can store in your code. You can then detour the device9->Present function.
Hope this makes sense. Detours 3 also have some samples of other ways to detouring COM. They are located in the 'Samples' folder after installing detours. There are also tutorials like: http://forum.cheatengine.org/viewtopic.php?t=161045 this uses the older version of detours 1.5. However the overall methodology is the same.

How can i set an entrypoint for a dll

First i thought entry point in dlls DLLMain but then when i try to import it in C# i get an error that entrypoint wasn't found Here is my code:
#include <Windows.h>
int Test(int x,int y)
{
return x+y;
}
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
MessageBox(0,L"Test",L"From unmanaged dll",0);
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
How can i set an entry point for my dll? And if you dont mind can you give me little explanation about entry point?
Like do i have to set import the same dll again and changing the entry point so i can use other functions in same dll? thanks in advance.
In your example, it seems you intend Test() to be an entry point however you aren't exporting it. Even if you begin exporting it, it might not work properly with C++ name "decoration" (mangling). I'd suggest redefining your function as:
extern "C" __declspec(dllexport) int Test(int x,int y)
The extern "C" component will remove C++ name mangling. The __declspec(dllexport) component exports the symbol.
See http://zone.ni.com/devzone/cda/tut/p/id/3056 for more detail.
Edit: You can add as many entry points as you like in this manner. Calling code merely must know the name of the symbol to retrieve (and if you're creating a static .lib, that takes care of it for you).

Global Keyboard hook not working

I have created a global Keyboard hook.
Hook is created in a DLL.
#pragma comment(linker, "/SECTION:.SHARED,RWS")
#pragma data_seg(".SHARED")
static HHOOK hkb=NULL;
static CMyFile *pLF;
#pragma data_seg()
HINSTANCE hins = NULL;
extern "C"
LRESULT __declspec(dllexport) __stdcall CALLBACK KeyBoardHookProc(
int nCode,
WPARAM wParam,
LPARAM lParam)
{
if (nCode < 0) {
return CallNextHookEx(0, nCode, wParam, lParam);
}
return CallNextHookEx(hkb, nCode, wParam, lParam);
}
extern "C"
LRESULT __declspec(dllexport) __stdcall CALLBACK Install()
{
pLF = new CMyFile(L"c:\\1.txt");
hkb = SetWindowsHookEx(WH_KEYBOARD,(HOOKPROC)KeyBoardHookProc,hins,0);
return 0;
}
extern "C"
BOOL __declspec(dllexport) __stdcall CALLBACK UnInstall()
{
return UnhookWindowsHookEx(hkb);
}
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch(ul_reason_for_call)
{
case DLL_PROCESS_ATTACH :
hins = (HINSTANCE) hModule;
break;
case DLL_THREAD_ATTACH :
break;
case DLL_THREAD_DETACH :
break;
case DLL_PROCESS_DETACH :
break;
}
return TRUE;
}
I have craeted one EXe that loads this dll and calls install function of the hook dll.
HMODULE hMod = LoadLibrary(L"hk.dll");
if(hMod!=NULL)
{
typedef LRESULT (__stdcall CALLBACK *_installhk)() ;
_installhk installProc;
installProc = (_installhk) GetProcAddress(hMod,"Install");
if(installProc!=NULL)
{
installProc();
}
}
While debugging breakpoint on KeyBoardHookProc is being hit only once when I launch the exe.
The exe keeps on running unless I close it but if I enter anything else from keyboard the hook procedure not getting called.
What could be the reason for this?
Is this not the right way to setup global keyboard hook?
How did you test that the hook procedure is not called ? If you tried to check it with a breakpoint, you have to take care that your hook dll is loaded in every process but your breakpoint is only put in your current process.
If you have any window in your application, focus on it before hitting keys or debug it using logs.
Another solution is to hook with WH_KEYBOARD_LL which does not require an extra DLL. You can hook directly from your process.
Have a look at the late Paul DiLascia's code which installs a global keyboard hook to trap the Ctrl+Alt+Del, Task Manager. MSDN September 2002 'Disabling keys in XP with TrapKeys'
Hope this helps,
Best regards,
Tom.
This may not be directly related to your main problem, but your use of the CMyFile object has several issues:
The CMyFile object is allocated dynamically using new CMyFile(...). This will create it only in the memory space of one process.
The pLF pointer is uninitialized. This means it will be placed in the BSS segment instead of the shared data segment. To fix this, declare it with CMyFile *pLF = NULL;.
CMyFile itself probably has members containing file handles and/or pointers which won't work properly in other processes.
Regarding your main question:
You seem to be creating the hook correctly as far as I can see.
There is no need to cast to HOOKPROC in the call to SetWindowsHookEx. If you get a warning without it, there is a problem with your function type.
There's no need for the if statement in the hook proc - the first parameter to CallNextHookEx is ignored anyway on modern Windows, so both branches effectively do the same thing.
I don't know if I'd trust debugger breakpoints on a hook procedure called from different processes - it's possible that the procedure is called but the debugger isn't catching it.
extern "C" is good it will get rid of the name mangling mentioned above but __stdcall will conflict with this.
You should use the RegisterHoyKey API call instead - it's much less hassle (as I found out myself recently when I replaced a similar keyboard hook DLL!).
Check your export section for DLL and see what name linker exported your "Install" function. C++ mangles with export function names. I bet you anything it is not "Install" but rather _Install#12 or something like that.