Detouring DrawText - c++

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.

Related

Can't find RequireSignedAppinit_DLLs in Registery

I am trying to do a small dll injection on my computer, and it doesn't seem to work.
I updated AppInit_DLLs with the path to my dll, and I read online that I need to set LoadAppinit_DLLs to 1 (which I have) and RequireSignedAppinit_DLLs to 0 for the injection to work.
but I can't find RequireSignedAppinit_DLLs in the registery..
My Registery
And here is my dll code: (It's very messy I am just trying to see if it will work before I actually make it clean)
#include "pch.h"
#define DLL_EXPORT
#include "mydll.h"
extern "C"
{
DECLDIR void Share()
{
MessageBox(NULL, (LPCWSTR)L"DLL injection!", (LPCWSTR)L"Hacked", 0);
}
void Keep()
{
MessageBox(NULL, (LPCWSTR)L"DLL injection!", (LPCWSTR)L"Hacked", 0);
}
DECLDIR void openWindow()
{
MessageBox(NULL, (LPCWSTR)L"DLL injection!", (LPCWSTR)L"Hacked", 0);
}
}
BOOL APIENTRY DllMain(HANDLE hModule, // Handle to DLL module
DWORD ul_reason_for_call,
LPVOID lpReserved) // Reserved
{
openWindow();
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
// A process is loading the DLL.
Keep();
Share();
openWindow();
break;
case DLL_THREAD_ATTACH:
// A process is creating a new thread.
Keep();
Share();
openWindow();
break;
case DLL_THREAD_DETACH:
// A thread exits normally.
Keep();
Share();
openWindow();
break;
case DLL_PROCESS_DETACH:
// A process unloads the DLL.
Keep();
Share();
openWindow();
break;
}
return TRUE;
}
Hope anyone can help...
Just create the RequireSignedAppinit_DLLs REG_WORD value yourself.
This is fine for experimentation but a real application should not modify these values because it decreases the security of the system.

Globally installed keyboard hook prevents keyboard input to other applications

I am setting a global hook for keyboard. When I give keyboard inputs to other applications, the application does not receive the input and it hangs. When the console is stopped, the application recovers and the keyboard inputs are posted together.
DLL source:
#include <iostream>
#include <Windows.h>
#include <string>
using namespace std;
#define DLLEXPORT __declspec(dllexport)
DLLEXPORT bool installhook();
DLLEXPORT void unhook();
DLLEXPORT string TestLoaded();
DLLEXPORT LRESULT CALLBACK KeyboardProc ( int code, WPARAM wParam, LPARAM lParam );
static HHOOK kb_hook;
string test = "not loaded";
HINSTANCE hDLL;
DLLEXPORT LRESULT CALLBACK KeyboardProc ( int code, WPARAM wParam, LPARAM lParam )
{
if(code == HC_ACTION) // if there is an incoming action and a key was pressed
{
switch(wParam)
{
case VK_SPACE:
printf("Space was pressed\n"); //tried without this also
MessageBoxA(NULL, "Hi", "Space", MB_OK);
break;
}
}
return CallNextHookEx(NULL, code, wParam, lParam);
}
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
test = "loaded";
switch(ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
hDLL = hModule;
break;
}
printf("test str = %s \n", test.c_str());
return TRUE;
}
bool installhook()
{
kb_hook = SetWindowsHookEx(WH_KEYBOARD, KeyboardProc, hDLL, NULL);
if(!kb_hook)
{
return false;
}
return true;
}
void unhook()
{
if(kb_hook)
{
UnhookWindowsHookEx(kb_hook);
}
}
string TestLoaded()
{
return test;
}
Console applicatioon source:
#include <iostream>
#include <Windows.h>
#include <string>
#define DLLIMPORT __declspec(dllimport)
using namespace std;
DLLIMPORT void unhook();
DLLIMPORT bool installhook();
DLLIMPORT string TestLoaded();
int main()
{
cout << TestLoaded() <<endl;
installhook();
for(int i = 1; i<=10 ; i++)
{
//Do some keyboard activities in this 10 secs
Sleep(1000);
cout << i<<endl;
}
unhook();
cin.get();
return 1;
}
My suspicion was that since the dll will be loaded into each process in the process's own address space and console would not be present in other applications, it gets void and crashed. So I removed the console outputs and replaced with messagebox. Then also no difference.
What could be the problem?
Update:
I tried to do a local hook to a specific thread before trying it global. But I get Parameter is incorrect error 87 at setwindowshookex. Below are the updated code:
dll:
bool installhook(DWORD ThreadId) //exporting this function
{
kb_hook = SetWindowsHookEx(WH_KEYBOARD, KeyboardProc, NULL, ThreadId); //tried with the dll module's handle also instead of NULL
if(!kb_hook)
{
printf("SetWindowsHookEx failed : %d\n", GetLastError());
return false;
}
return true;
}
Console application source:
DWORD myThread()
{
cout<< "Thread started\n";
char str[250];
cin>>str;
return 0;
}
int main()
{
cout << TestLoaded() <<endl;
DWORD myThreadID;
HANDLE myHandle = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)myThread, NULL, 0, &myThreadID);
installhook(myThreadID);
for(int i = 0; i<100 ; i++)
{
Sleep(100);
if(i%10 == 0)
{
cout << i<<endl;
}
}
unhook();
}
Try to use WH_KEYBOARD_LL. You can set global hook even without dll declaring hook function in you process. Plus, you should detect space action using PKBDLLHOOKSTRUCT struct
LRESULT CALLBACK KeyboardProc ( int code, WPARAM wParam, LPARAM lParam )
{
if ( code == HC_ACTION )
{
switch ( wParam )
{
case WM_KEYDOWN:
{
// Get hook struct
PKBDLLHOOKSTRUCT p = ( PKBDLLHOOKSTRUCT ) lParam;
if ( p->vkCode == VK_SPACE)
{
MessageBoxA( NULL, "Hi", "Space", MB_OK );
}
}
break;
}
}
return CallNextHookEx( NULL, code, wParam, lParam );
}
....
// Somewhere in code
kb_hook = SetWindowsHookEx( WH_KEYBOARD_LL, KeyboardProc, NULL, NULL );
Thanks for all the inputs in answers and comments.
I have found out the actual problem. The mistake I made was trying to use console window without any message queue.
If I understand correctly, console windows are hosted by conhost.exe and they don't have any message pumps. And the hook works correctly only if the application which installs it has a message queue (should explore more on why it's this way). See below for ways you can make it work
If you are not posting any message to the console application:
Replace the for loop in the console application's main with this:
MSG msg;
while(GetMessage(&msg, NULL, 0, 0) > 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
In case you are posting any message to the console application:
Create a window using CreateWindowEx, there is an option for a message only window also. You would have to create a class and assign a CALLBACK process. Read here for more details. Create that and pass the handle along to the hook dll and postmessage to the handle. Use the loop for Getting msg and dispatching it (mentioned above). Then all the messages you post the dummy window from your hook dll can be processed using the CALLBACK window process.
References:
Why must SetWindowsHookEx be used with a windows message queue
CreateWindowEx MSDN
I had the same issue, working with QT, the GUI would be blocked (as planned) but whenever it came back online, it would process my keyboard and mouse clicks.
I am not sure if this is the most efficient way of handling it, but to solve this, I handled all the keyboard and mouse events separately. If, some task was in progress, I would just ignore the key event.
Otherwise I guess it just queues up and waits for its' turn!

Windows Global Hook C++

I've been reading posts all over and trying different approaches, but I can't make this work.
I want to be able to track the last window before the user clicks on my application. This way I can bring it to the front and send a copy command to retrieve whatever the user has selected.
I thought about using hooks to receive notifications of activated windows, but it is not working as expected. I'm using HSHELL_WINDOWACTIVATED global hook to keep track of the current and last active window, but I always get both handles to be the same, pointing to my application.
The code looks like:
#pragma data_seg("ASEG")
HWND lastWindow = 0;
HWND currentWindow = 0;
#pragma data_seg()
#pragma comment(linker, "/section:ASEG,RWS")
HINSTANCE dllHandle;
BOOL APIENTRY DllMain(
HINSTANCE hinstDLL,
DWORD fdwReason,
PVOID lpReserved )
{
switch( fdwReason )
{
case DLL_PROCESS_ATTACH:
dllHandle = hinstDLL;
return TRUE;
break;
}
}
LRESULT CALLBACK ShellHookProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode > 0)
{
switch (nCode)
{
case HSHELL_WINDOWACTIVATED: lastWindow = currentWindow;
currentWindow = (HWND)wParam;
break;
}
}
return ::CallNextHookEx(NULL, nCode,wParam,lParam);
}
extern "C" {
__declspec(dllexport) void Init()
{
SetWindowsHookEx(WH_SHELL, ShellHookProc, dllHandle, 0);
}
}
Later on I would use the lastWindow to bring that window to the front and send a Ctrl+C command.
If you call GetWindowTextA(..) for each handle, the first time you activate a different window and go back to the application, lastWindow retrieves blank and currentWindow my application name. Any consecutive activations retrieve always the name of my application for both lastWindow and currentWindow.
I don't quite understand why this is happening. Any ideas?
Thanks!
I think you can use SetWinEventHook. This hook should allow you to capture the EVENT_SYSTEM_FOREGROUND message so that each time a window is brought to the foreground, you can capture the window handle. Then when your app window is activated, just look at the last value you captured.
See this: https://stackoverflow.com/a/4407715/1502289
Also, in your own code, you could simply do a comparison to see if the window handle is the handle to your own window. If not, save the handle.
Example:
...
case HSHELL_WINDOWACTIVATED:
if (lastWindow != [your own window's handle])
{
lastWindow = (HWND)wParam;
}
break;
...

WinAPI window doesn't appear

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.

How can I set up a CBT hook on a Win32 console window?

I've been trying to set up a CBT hook for my C++ Console application with the following code:
...includes...
typedef struct _HOOKDATA
{
int type;
HOOKPROC hookproc;
HHOOK hhook;
}_HOOKDATA;
_HOOKDATA hookdata;
//CBT
LRESULT CALLBACK CBTProc(int code, WPARAM wParam, LPARAM lParam)
{
//do not proccess message
if(code < 0)
{
cout<<"code less than 0"<<endl;
return CallNextHookEx(hookdata.hhook,code,wParam,lParam);
}
switch(code)
{
case HCBT_ACTIVATE:
break;
case HCBT_CREATEWND:
cout<<"CREATEWND"<<endl;
break;
case HCBT_MINMAX:
cout<<"MINMAX"<<endl;
break;
default: //unknown
cout<<"DEFAULT"<<endl;
break;
}
return CallNextHookEx(hookdata.hhook, code, wParam, lParam);
}
int main()
{
hookdata.type = WH_CBT;
hookdata.hookproc = CBTProc;
hookdata.hhook = ::SetWindowsHookEx(hookdata.type, CBTProc,
GetModuleHandle( 0 ), GetCurrentThreadId());
if(hookdata.hhook == NULL)
{
cout<<"FAIL"<<endl;
system("pause");
}
system("pause");
return 0;
}
The program seems to be working because there is not compile errors nor run time errors. Also I do not get a 'FAIL' message stated in the main() function meaning SetWindowHookEx is working OK. However, I don't get any of the messages stated in the CBTProc function; not even the 'DEFAULT' message. Can anyone pin-point what is the logic error in the code?
Thanks.
The problem is that SetWindowHookEx is based upon the Win32 message handling model. Console windows are children of the Kernel itself and do not create their own message pumps or windows.
AFAIK doing what you want directly is not possible.